diff --git a/AndroidKernel.mk b/AndroidKernel.mk index 1ba0b65f2adc..a5ebdf129058 100644 --- a/AndroidKernel.mk +++ b/AndroidKernel.mk @@ -34,7 +34,7 @@ KERNEL_HEADER_ARCH := $(TARGET_KERNEL_HEADER_ARCH) endif ifeq ($(shell echo $(KERNEL_DEFCONFIG) | grep vendor),) -KERNEL_DEFCONFIG := vendor/$(KERNEL_DEFCONFIG) +KERNEL_DEFCONFIG := $(KERNEL_DEFCONFIG) endif KERNEL_HEADER_DEFCONFIG := $(strip $(KERNEL_HEADER_DEFCONFIG)) diff --git a/Documentation/devicetree/bindings/arm/msm/android.txt b/Documentation/devicetree/bindings/arm/msm/android.txt index 32e418fd01fb..7b8b7909bae3 100644 --- a/Documentation/devicetree/bindings/arm/msm/android.txt +++ b/Documentation/devicetree/bindings/arm/msm/android.txt @@ -53,38 +53,6 @@ Example: }; }; -odm: ------------------ - -odm partition specification. - -Required properties: - --compatible: "android, odm" --dev: block device corresponding to odm partition --type: file system type of odm partition --mnt_flags: mount flags --fsmgr_flags: fsmgr flags - -Example: - - firmware: firmware { - android { - compatible = "android,firmware"; - fstab { - compatible = "android,fstab"; - odm { - compatible = "android,odm"; - dev = "/dev/block/platform/soc/1da4000.ufshc/by-name/odm"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait,slotselect"; - status = "ok"; - }; - }; - }; - }; - system: ----------------- diff --git a/Documentation/devicetree/bindings/i2c/i2c.txt b/Documentation/devicetree/bindings/i2c/i2c.txt index cee9d5055fa2..ecdc8c9f8ef5 100644 --- a/Documentation/devicetree/bindings/i2c/i2c.txt +++ b/Documentation/devicetree/bindings/i2c/i2c.txt @@ -73,6 +73,9 @@ wants to support one of the below features, it should adapt the bindings below. - wakeup-source device can be used as a wakeup source. +- async-suspend + device supports async suspend/resume. + - reg I2C slave addresses diff --git a/Documentation/devicetree/bindings/media/spi-ir.txt b/Documentation/devicetree/bindings/media/spi-ir.txt new file mode 100644 index 000000000000..2232d92bcc00 --- /dev/null +++ b/Documentation/devicetree/bindings/media/spi-ir.txt @@ -0,0 +1,24 @@ +Device tree bindings for IR LED connected through SPI bus which is used as +remote controller. + +The IR LED switch is connected to the MOSI line of the SPI device and the data +are delivered thourgh that. + +Required properties: + - compatible: should be "ir-spi" + +Optional properties: + - irled,switch: specifies the gpio switch which enables the irled + +Example: + + irled@0 { + compatible = "ir-spi"; + reg = <0x0>; + spi-max-frequency = <5000000>; + irled,switch = <&gpr3 3 0>; + + controller-data { + samsung,spi-feedback-delay = <0>; + }; + }; diff --git a/Makefile b/Makefile index 19cc680ad012..38bcdce81797 100644 --- a/Makefile +++ b/Makefile @@ -1300,7 +1300,7 @@ headers_install: __headers $(error Headers not exportable for the $(SRCARCH) architecture)) $(Q)$(MAKE) $(hdr-inst)=include/uapi dst=include $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi $(hdr-dst) - $(Q)$(MAKE) $(hdr-inst)=techpack + $(Q)$(MAKE) $(hdr-inst)=techpack/audio/include/uapi dst=techpack/audio/include PHONY += headers_check_all headers_check_all: headers_install_all @@ -1310,7 +1310,7 @@ PHONY += headers_check headers_check: headers_install $(Q)$(MAKE) $(hdr-inst)=include/uapi dst=include HDRCHECK=1 $(Q)$(MAKE) $(hdr-inst)=arch/$(hdr-arch)/include/uapi $(hdr-dst) HDRCHECK=1 - $(Q)$(MAKE) $(hdr-inst)=techpack HDRCHECK=1 + $(Q)$(MAKE) $(hdr-inst)=techpack/audio/include/uapi dst=techpack/audio/include HDRCHECK=1 # --------------------------------------------------------------------------- # Kernel selftest diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig index 0668ea29ca9c..1a4e436d490b 100644 --- a/arch/arm64/Kconfig +++ b/arch/arm64/Kconfig @@ -1465,3 +1465,30 @@ source "arch/arm64/crypto/Kconfig" endif source "lib/Kconfig" + +menu "Xiaomi configuration options" + +config MACH_XIAOMI + bool "Xiaomi device" + depends on ARCH_QCOM + help + Support for Xiaomi products + +config MACH_XIAOMI_SM8150 + bool "Xiaomi SM8150" + depends on ARCH_SM8150 + select MACH_XIAOMI + help + Support for SM8150-based Xiaomi variants + +menu "Xiaomi board selection" + +config MACH_XIAOMI_CEPHEUS + bool "polaris board" + select MACH_XIAOMI_SM8150 + help + Support for Xiaomi MI 9 + +endmenu + +endmenu diff --git a/arch/arm64/boot/dts/qcom/Makefile b/arch/arm64/boot/dts/qcom/Makefile index c79b3e08c918..7e5808b42ac0 100644 --- a/arch/arm64/boot/dts/qcom/Makefile +++ b/arch/arm64/boot/dts/qcom/Makefile @@ -1,3 +1,11 @@ +ifeq ($(CONFIG_MACH_XIAOMI_SM8150),y) +ifeq ($(CONFIG_BUILD_ARM64_DT_OVERLAY),y) +dtbo-$(CONFIG_ARCH_SM8150) += \ + cepheus-sm8150-overlay.dtbo + +cepheus-sm8150-overlay.dtbo-base := sm8150.dtb sm8150-v2.dtb sm8150p.dtb sm8150p-v2.dtb +endif +else # SPDX-License-Identifier: GPL-2.0 dtb-$(CONFIG_ARCH_QCOM) += apq8016-sbc.dtb dtb-$(CONFIG_ARCH_QCOM) += apq8096-db820c.dtb @@ -311,6 +319,7 @@ dtb-$(CONFIG_ARCH_SDXPRAIRIE) += sdxprairie-rumi.dtb \ sa515m-ccard.dtb \ sa515m-ccard-pcie-ep.dtb \ sa515m-ccard-usb-ep.dtb +endif ifeq ($(CONFIG_ARM64),y) always := $(dtb-y) diff --git a/arch/arm64/boot/dts/qcom/batterydata-F1-atl-3300mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-F1-atl-3300mah.dtsi new file mode 100644 index 000000000000..721e6697a99b --- /dev/null +++ b/arch/arm64/boot/dts/qcom/batterydata-F1-atl-3300mah.dtsi @@ -0,0 +1,155 @@ +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +qcom,scud { + qcom,profile-revision = <24>; + /* #3675702_Xiaomi_F1sun_3300mAh_averaged_MasterSlave_Oct22nd2018*/ + qcom,fastchg-current-ma = <4800>; + qcom,jeita-fcc-ranges = <0 50 300000 + 51 100 1600000 + 101 150 3200000 + 151 450 4800000 + 451 580 1600000>; + qcom,jeita-fv-ranges = <0 50 4400000 + 51 100 4400000 + 101 150 4400000 + 151 450 4400000 + 451 580 4100000>; + qcom,step-chg-ranges = <3600000 4200000 3000000 + 4201000 4300000 3000000 + 4301000 4340000 2500000>; + qcom,dynamic-fv-ranges = <0 100 4400000 + 101 200 4380000 + 201 300 4360000 + 301 400 4340000 + 401 500 4340000>; + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,nom-batt-capacity-mah = <3300>; + qcom,batt-id-kohm = <68>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,battery-type = "f1_atl"; + qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; + qcom,therm-center-offset = <0x70>; + qcom,therm-pull-up = <100>; + qcom,rslow-normal-coeffs = <0x85 0x01 0x71 0x13>; + qcom,rslow-low-coeffs = <0xc6 0x15 0x65 0x02>; + qcom,checksum = <0xBE6A>; + qcom,gui-version = "PM855GUI - 1.0.0.10"; + qcom,fg-profile-data = [ + A9 1F 09 EA + 30 D4 F1 DA + 38 D5 00 00 + 5A BD 85 8A + FA 87 7F A4 + 75 92 06 81 + 1B FC 85 01 + 71 13 39 FC + 86 01 CE 1F + 32 0A 5D EB + DA ED B1 D4 + 2D 0A 69 D4 + 27 BD E8 1A + AB FB 8F BA + 60 00 4E FC + 47 FD 44 F4 + 33 33 30 10 + 35 0B 43 00 + 40 01 43 00 + 43 00 60 00 + 37 00 3C 00 + 46 00 40 00 + 39 00 76 00 + 5C 64 46 00 + 3F 00 3D 08 + 60 00 4C 00 + 49 00 57 10 + 4D 10 47 00 + 86 28 5E 48 + 4F 60 46 0D + 4E 00 D8 F8 + FE 1F 0C 0D + D4 FA 17 06 + 89 1C 32 0B + C5 0D 67 2A + 18 17 85 42 + 1E 5D 45 02 + 6C 10 36 1F + 09 04 31 0A + 25 FD DD 1C + 05 02 A3 05 + BE 02 3F 17 + 1C 22 05 44 + 91 52 70 12 + 60 1F DE E5 + 4D CA E9 A4 + E5 1C 7D C9 + 8C 05 08 BB + 1C 17 D9 8B + BF 84 BF 93 + 83 A0 09 80 + D3 03 01 05 + 21 FC 8D FA + 00 F8 59 D5 + FF EA F6 07 + DD F3 10 CD + 92 18 16 F0 + 2F D7 26 02 + 57 05 2B 02 + CE 01 32 00 + 15 03 28 03 + D9 05 44 07 + 43 02 94 04 + 55 03 8F 05 + 51 03 49 00 + 3A 00 42 00 + 43 64 48 00 + 4C 00 42 08 + 49 00 4A 00 + 49 00 3B 10 + 3A 10 3A 00 + 4A 20 4C 48 + 56 58 64 0E + 42 00 4D 00 + 58 08 61 00 + 50 00 3F 00 + 3F 10 4F 10 + 4C 00 5B 20 + 6D 40 48 58 + 54 0F 59 00 + 50 00 31 08 + D8 00 9F 20 + C9 04 F1 0A + ED 0D D7 1C + 19 23 F5 45 + 17 52 71 18 + D6 03 FA 05 + F6 02 73 12 + 3F 0A DC 1F + 6D 05 A4 02 + 1C 06 C0 1C + 0E 03 EC 05 + 44 02 7A 18 + 81 03 8E 04 + 5B 02 6A 00 + 2D 20 03 05 + FC 02 C3 05 + E3 1C 1C 02 + BA 05 80 02 + 92 18 EF 02 + 90 05 CD 02 + 7C 00 3B 01 + C0 00 FA 00 + BB 0C 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/batterydata-F1-coslight-3300mah.dtsi b/arch/arm64/boot/dts/qcom/batterydata-F1-coslight-3300mah.dtsi new file mode 100644 index 000000000000..9355d5563441 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/batterydata-F1-coslight-3300mah.dtsi @@ -0,0 +1,155 @@ +/* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +qcom,coslight { + qcom,profile-revision = <24>; + /* #3675676_Xiaomi_F1cos_3300mAh_averaged_MasterSlave_Oct22nd2018*/ + qcom,fastchg-current-ma = <4800>; + qcom,jeita-fcc-ranges = <0 50 300000 + 51 100 1600000 + 101 150 3200000 + 151 450 4800000 + 451 580 1600000>; + qcom,jeita-fv-ranges = <0 50 4400000 + 51 100 4400000 + 101 150 4400000 + 151 450 4400000 + 451 580 4100000>; + qcom,step-chg-ranges = <3600000 4200000 3000000 + 4201000 4300000 3000000 + 4301000 4340000 2500000>; + qcom,dynamic-fv-ranges = <0 100 4400000 + 101 200 4380000 + 201 300 4360000 + 301 400 4340000 + 401 500 4340000>; + qcom,max-voltage-uv = <4400000>; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,nom-batt-capacity-mah = <3300>; + qcom,batt-id-kohm = <100>; + qcom,battery-beta = <4250>; + qcom,therm-room-temp = <100000>; + qcom,battery-type = "f1_cos"; + qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; + qcom,therm-center-offset = <0x70>; + qcom,therm-pull-up = <100>; + qcom,rslow-normal-coeffs = <0xe4 0x04 0x3a 0x12>; + qcom,rslow-low-coeffs = <0x21 0x15 0x15 0x06>; + qcom,checksum = <0xC822>; + qcom,gui-version = "PM855GUI - 1.0.0.10"; + qcom,fg-profile-data = [ + A9 1F 6C EA + 8F E5 33 EA + 8C E5 00 00 + C4 BC AC 8A + FC 87 EC 82 + 71 87 10 80 + 20 FC E4 04 + 3A 12 C9 04 + 0F 02 CE 1F + 32 0A FB EB + 65 ED 6E DC + F6 0A FA DC + 38 C5 3A 12 + 84 02 D1 D3 + 60 00 36 FC + 3D FD 3E F4 + 38 33 30 10 + 33 0B 37 00 + 3F 01 47 00 + 4D 00 60 00 + 36 00 3B 00 + 3D 00 38 00 + 35 00 6A 00 + 4D 64 42 00 + 3F F8 42 00 + 60 F0 55 00 + 5E 00 84 08 + 64 08 5D 00 + BB 20 7D 40 + 67 58 60 10 + 6C 00 D8 F8 + 05 1F EF 04 + 76 EB 6A 04 + D2 1C 6D 0A + F9 0C 5E 2B + 96 18 55 4B + CD 5C 20 02 + 6A 0F 86 1E + E3 05 A8 02 + 42 04 C5 1C + 78 02 9C 04 + FD 03 AC 17 + 1E 22 D0 45 + 19 5B 5F 11 + AB 1E C3 EE + FC CA 59 C7 + DE 1C A1 C9 + E4 04 AA BB + 92 17 D8 93 + 78 84 37 A2 + 78 A0 09 80 + 46 02 82 04 + 66 05 FF FB + 00 F8 68 DC + 06 EA F3 FF + 77 E3 FA C4 + 15 18 16 00 + 0E E7 FE 02 + F3 05 CB 02 + CE 01 32 00 + 15 03 CA 02 + D1 05 5B 03 + 27 04 F4 03 + 9D 03 94 02 + D2 05 54 00 + 3F 00 40 00 + 44 64 47 00 + 46 E8 47 F8 + 49 E8 48 00 + 4A 00 45 10 + 4F 10 3E 00 + 49 28 4B 48 + 53 58 62 0D + 40 00 4E F8 + 52 00 58 F8 + 4D 00 47 00 + 43 10 54 10 + 52 00 66 28 + 7E 48 4D 60 + 5D 0D 5E 00 + 50 F8 36 00 + D8 F0 A7 1E + 12 04 6F 0A + 87 0A E3 1C + 43 23 A7 45 + 95 5A 8C 18 + 08 02 B3 05 + 9E 03 5A 10 + 3F 0A 6B 1F + 33 04 E7 03 + D7 05 B6 1C + 4B 03 A7 05 + 92 02 6D 18 + 15 02 8D 05 + 00 02 64 00 + 05 1F EF 04 + 76 03 6A 04 + D2 1C 6D 02 + F9 04 5E 03 + 96 18 55 03 + CD 04 20 02 + 6A 00 56 01 + C0 00 FA 00 + F0 0C 00 00 + ]; +}; diff --git a/arch/arm64/boot/dts/qcom/cepheus-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/cepheus-audio-overlay.dtsi new file mode 100644 index 000000000000..a76bb80b1ff5 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/cepheus-audio-overlay.dtsi @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#include "sm8150-audio-overlay.dtsi" + +&snd_934x { + qcom,audio-routing = + "AIF4 VI", "MCLK", + "RX_BIAS", "MCLK", + "MADINPUT", "MCLK", + "hifi amp", "LINEOUT1", + "hifi amp", "LINEOUT2", + "AMIC2_EXT_0", "MIC BIAS2", + "MIC BIAS2", "Headset Mic", + "AMIC2_EXT_1", "MIC BIAS1", + "MIC BIAS1", "Headset Mic2", + "AMIC3", "MIC BIAS3", + "MIC BIAS3", "ANCRight Headset Mic", + "AMIC1", "MIC BIAS1", + "MIC BIAS1", "ANCLeft Headset Mic", + "AMIC4", "MIC BIAS3", + "MIC BIAS3", "ANCRight Headset Mic", + "AMIC5", "MIC BIAS4", + "MIC BIAS4", "Analog Mic5"; + + qcom,uart-audio-sw-gpio = <&sbu_uart_en>; + qcom,adc2-switch-gpio = <&adc2_switch_gpio>; + qcom,msm-mbhc-usbc-audio-supported = <1>; + qcom,fsa4476-gpio-support = <1>; + qcom,usbc-analog-en1-gpio = <&wcd_usbc_analog_en1_gpio>; + qcom,usbc-analog-en2-gpio = <&tlmm 58 0>; + + pinctrl-names = "quat_mi2s_enable", "quat_mi2s_disable", + "quat_tdm_enable", "quat_tdm_disable", + "aud_active", "aud_sleep"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active &quat_mi2s_sd1_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_sd0_sleep &quat_mi2s_sd1_sleep>; + pinctrl-2 = <&quat_tdm_active &quat_tdm_dout_active>; + pinctrl-3 = <&quat_tdm_sleep &quat_tdm_dout_sleep>; + pinctrl-4 = <&wcd_usbc_analog_en2_active>; + pinctrl-5 = <&wcd_usbc_analog_en2_idle>; +}; + +&soc { + sbu_uart_en: msm_cdc_pinctrl@25 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&sbu_uart_en_active>; + pinctrl-1 = <&sbu_uart_en_idle>; + }; + + adc2_switch_gpio: msm_cdc_pinctrl@142 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&adc2_switch_gpio_active>; + pinctrl-1 = <&adc2_switch_gpio_idle>; + }; + + wcd_usbc_analog_en1_gpio: msm_cdc_pinctrl@49 { + compatible = "qcom,msm-cdc-pinctrl"; + pinctrl-names = "aud_active", "aud_sleep"; + pinctrl-0 = <&wcd_usbc_analog_en1_active>; + pinctrl-1 = <&wcd_usbc_analog_en1_idle>; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/cepheus-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/cepheus-pinctrl.dtsi new file mode 100644 index 000000000000..7aeb99e672df --- /dev/null +++ b/arch/arm64/boot/dts/qcom/cepheus-pinctrl.dtsi @@ -0,0 +1,539 @@ +/*for xiaomi pinctrl*/ +&tlmm { + pmx_ts_active { + ts_active: ts_active { + mux { + pins = "gpio122", "gpio12"; + function = "gpio"; + }; + config { + pins = "gpio122", "gpio12"; + drive-strength = <8>; + bias-pull-up; + }; + }; + }; + + pmx_ts_int_suspend { + ts_int_suspend: ts_int_suspend { + mux { + pins = "gpio122"; + function = "gpio"; + }; + config { + pins = "gpio122"; + drive-strength = <2>; + bias-pull-down; + input-enable; + }; + }; + }; + + pmx_ts_reset_suspend { + ts_reset_suspend: ts_reset_suspend { + mux { + pins = "gpio12"; + function = "gpio"; + }; + config { + pins = "gpio12"; + drive-strength = <2>; + bias-disable; + output-low; + }; + }; + }; + + idt { + idt_int_active: idt_int_active { + /* active state */ + mux { + /* GPIO 78 idt Read Interrupt */ + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + input-enable; + }; + }; + + idt_int_suspend: idt_int_suspend { + /* sleep state */ + mux { + /* GPIO 78 idt Read Interrupt */ + pins = "gpio90"; + function = "gpio"; + }; + + config { + pins = "gpio90"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + input-enable; + }; + }; + + idt_enable_active: idt_enable_active { + /* active state */ + mux { + /* GPIO 36 idt enable pin */ + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-disable; + bias-pull-down; + output-low; + }; + }; + + idt_enable_suspend: idt_enable_suspend { + /* sleep state */ + mux { + /* GPIO 36 idt enable pin */ + pins = "gpio104"; + function = "gpio"; + }; + + config { + pins = "gpio104"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + adc2_switch_gpio_ctrl { + adc2_switch_gpio_idle: adc2_switch_idle { + mux { + pins = "gpio142"; + function = "gpio"; + }; + config { + pins = "gpio142"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + adc2_switch_gpio_active: adc2_switch_active { + mux { + pins = "gpio142"; + function = "gpio"; + }; + config { + pins = "gpio142"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + sbu_uart_en_ctrl { + sbu_uart_en_idle: uart_audio_en_idle { + mux { + pins = "gpio25"; + function = "gpio"; + }; + config { + pins = "gpio25"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + sbu_uart_en_active: uart_audio_en_active { + mux { + pins = "gpio25"; + function = "gpio"; + }; + config { + pins = "gpio25"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + ai_key_ctrl { + ai_key_active_default: ai_key_active { + mux { + pins = "gpio97"; + function = "gpio"; + }; + config { + pins = "gpio97"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + + }; + + ai_key_idle_default: ai_key_idle { + mux { + pins = "gpio97"; + function = "gpio"; + }; + config { + pins = "gpio97"; + drive-strength = <2>; + bias-pull-up; + input-enable; + }; + }; + }; + + pcie1 { + pcie1_wake_default: pcie1_wake_default { + mux { + pins = "gpio114"; + function = "gpio"; + }; + + config { + pins = "gpio114"; + drive-strength = <2>; + bias-pull-up; + }; + }; + }; + + nfc { + nfc_int_active: nfc_int_active { + /* active state */ + mux { + /* GPIO 47 NFC Read Interrupt */ + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_int_suspend: nfc_int_suspend { + /* sleep state */ + mux { + /* GPIO 47 NFC Read Interrupt */ + pins = "gpio47"; + function = "gpio"; + }; + + config { + pins = "gpio47"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_active: nfc_enable_active { + /* active state */ + mux { + /* 41: NFC ENABLE 42:ESE Enable */ + pins = "gpio48", "gpio103"; + function = "gpio"; + }; + + config { + pins = "gpio48", "gpio103"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_enable_suspend: nfc_enable_suspend { + /* sleep state */ + mux { + /* 41: NFC ENABLE 42:ESE Enable */ + pins = "gpio48", "gpio103"; + function = "gpio"; + }; + + config { + pins = "gpio48", "gpio103"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + + nfc_clk_req_active: nfc_clk_req_active { + /* active state */ + mux { + /* 113: NFC CLOCK REQUEST */ + pins = "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio113"; + drive-strength = <2>; /* 2 MA */ + bias-pull-up; + }; + }; + + nfc_clk_req_suspend: nfc_clk_req_suspend { + /* sleep state */ + mux { + /* 113: NFC CLOCK REQUEST */ + pins = "gpio113"; + function = "gpio"; + }; + + config { + pins = "gpio113"; + drive-strength = <2>; /* 2 MA */ + bias-disable; + }; + }; + }; + +}; +//camera voltage start +&cam_sensor_mclk0_active { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-disable; /* No PULL */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk0_suspend { + /* MCLK0 */ + mux { + pins = "gpio13"; + function = "cam_mclk"; + }; + + config { + pins = "gpio13"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk1_active { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-disable; /* No PULL */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk1_suspend { + /* MCLK1 */ + mux { + pins = "gpio14"; + function = "cam_mclk"; + }; + + config { + pins = "gpio14"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk2_active { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-disable; /* No PULL */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk2_suspend { + /* MCLK2 */ + mux { + pins = "gpio15"; + function = "cam_mclk"; + }; + + config { + pins = "gpio15"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk3_active { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-disable; /* No PULL */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_mclk3_suspend { + /* MCLK3 */ + mux { + pins = "gpio16"; + function = "cam_mclk"; + }; + + config { + pins = "gpio16"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <4>; /* 2 MA */ + }; +}; + +&cam_sensor_active_rear { + /* RESET REAR2 */ + mux { + pins = "gpio30", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio30", "gpio59"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +&cam_sensor_suspend_rear { + /* RESET REAR2 */ + mux { + pins = "gpio30", "gpio59"; + function = "gpio"; + }; + + config { + pins = "gpio30", "gpio59"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&cam_sensor_active_rear_aux { + /* RESET REARAUX, VANA REARAUX */ + mux { + pins = "gpio23", "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio23", "gpio29"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +&cam_sensor_suspend_rear_aux { + /* RESET REARAUX, VANA REARAUX */ + mux { + pins = "gpio23", "gpio29"; + function = "gpio"; + }; + + config { + pins = "gpio23", "gpio29"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&cam_sensor_active_front { + /* RESET FRONT, VANA FRONT*/ + mux { + //pins = "gpio54","gpio132","gpio118"; + pins = "gpio54","gpio118"; + function = "gpio"; + }; + + config { + //pins = "gpio54","gpio132","gpio118"; + pins = "gpio54","gpio118"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +&cam_sensor_suspend_front { + /* RESET FRONT, VANA FRONT*/ + mux { + //pins = "gpio54","gpio132","gpio118"; + pins = "gpio54","gpio118"; + function = "gpio"; + }; + + config { + //pins = "gpio54","gpio132","gpio118"; + pins = "gpio54","gpio118"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +&cam_sensor_active_iris { + /* RESET ULTRA, VANA VDIG ULTRA*/ + mux { + pins = "gpio28","gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio28","gpio94"; + bias-disable; /* No PULL */ + drive-strength = <2>; /* 2 MA */ + }; +}; + +&cam_sensor_suspend_iris { + /* RESET ULTRA, VANA VDIG ULTRA*/ + mux { + pins = "gpio28","gpio94"; + function = "gpio"; + }; + + config { + pins = "gpio28","gpio94"; + bias-pull-down; /* PULL DOWN */ + drive-strength = <2>; /* 2 MA */ + output-low; + }; +}; + +//camera voltage end diff --git a/arch/arm64/boot/dts/qcom/cepheus-sm8150-camera-sensor-mtp.dtsi b/arch/arm64/boot/dts/qcom/cepheus-sm8150-camera-sensor-mtp.dtsi new file mode 100644 index 000000000000..dc4bcf1cfed3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/cepheus-sm8150-camera-sensor-mtp.dtsi @@ -0,0 +1,532 @@ +/* + * Copyright (c) 2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +&soc { + led_flash_rear: qcom,camera-flash@0 { + cell-index = <0>; + reg = <0x00 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_rear_aux1: qcom,camera-flash@1 { + cell-index = <1>; + reg = <0x01 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + led_flash_front: qcom,camera-flash@2 { + cell-index = <2>; + reg = <0x02 0x00>; + compatible = "qcom,camera-flash"; + wled-flash-support; + flash-source = <&wled_flash>; + torch-source = <&wled_torch>; + switch-source = <&wled_switch>; + status = "ok"; + }; + + led_flash_rear_aux2: qcom,camera-flash@3 { + cell-index = <3>; + reg = <0x03 0x00>; + compatible = "qcom,camera-flash"; + flash-source = <&pm8150l_flash0 &pm8150l_flash1>; + torch-source = <&pm8150l_torch0 &pm8150l_torch1>; + switch-source = <&pm8150l_switch2>; + status = "ok"; + }; + + camera_viodd_ldo: gpio-regulator@0 { + compatible = "regulator-fixed"; + reg = <0x00 0x00>; + regulator-name = "camera_viodd_ldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&tlmm 132 0>; + vin-supply = <&pm8150_s4>; + }; + + actuator_rear_regulator: gpio-regulator@1 { + compatible = "regulator-fixed"; + reg = <0x01 0x00>; + regulator-name = "actuator_rear_regulator"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&tlmm 24 0>; + vin-supply = <&pm8150l_bob>; + }; + + actuator_rear_aux_ldo: gpio-regulator@2 { + compatible = "regulator-fixed"; + reg = <0x02 0x00>; + regulator-name = "actuator_rear_aux_ldo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&tlmm 152 0>; + vin-supply = <&pm8150l_bob>; + }; + + actuator_ultra_ldo: gpio-regulator@3 { + compatible = "regulator-fixed"; + reg = <0x03 0x00>; + regulator-name = "actuator_ultra_ldo"; + regulator-min-microvolt = <2800000>; + regulator-max-microvolt = <2800000>; + regulator-enable-ramp-delay = <135>; + enable-active-high; + gpio = <&tlmm 95 0>; + vin-supply = <&pm8150l_bob>; + }; +}; + +&cam_cci1 { + qcom,cam-res-mgr { + compatible = "qcom,cam-res-mgr"; + status = "ok"; + }; + + actuator_rear: qcom,actuator@0 { + cell-index = <0>; + reg = <0x0>; + compatible = "qcom,actuator"; + cci-device = <0>; + cci-master = <1>; + cam_vaf-supply = <&actuator_rear_regulator>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_rear_aux: qcom,actuator@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,actuator"; + cci-device = <1>; + cci-master = <1>; + cam_vaf-supply = <&actuator_rear_aux_ldo>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_front: qcom,actuator@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,actuator"; + cci-master = <1>; + cam_vaf-supply = <&actuator_rear_aux_ldo>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + actuator_ultra_rear: qcom,actuator@3 { + cell-index = <3>; + reg = <0x3>; + compatible = "qcom,actuator"; + cci-master = <0>; + cam_vaf-supply = <&actuator_ultra_ldo>; + regulator-names = "cam_vaf"; + rgltr-cntrl-support; + rgltr-min-voltage = <2800000>; + rgltr-max-voltage = <2800000>; + rgltr-load-current = <0>; + }; + + eeprom_rear: qcom,eeprom@0 { + cell-index = <0>; + reg = <0>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_viodd_ldo>; + cam_vana-supply = <&pm8150_s5>; + cam_vdig-supply = <&pm8150_l17>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 1904000 2856000 0>; + rgltr-max-voltage = <1800000 2040000 3008000 0>; + rgltr-load-current = <180000 112000 519000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 14 0>, + <&tlmm 30 0>, + <&tlmm 59 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG0"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_aux: qcom,eeprom@1 { + cell-index = <1>; + reg = <0x1>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_viodd_ldo>; + cam_vana-supply = <&pm8150_s5>; + cam_vdig-supply = <&pm8150_l17>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 1904000 2856000 0>; + rgltr-max-voltage = <1800000 2040000 3008000 0>; + rgltr-load-current = <180000 112000 519000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 14 0>, + <&tlmm 30 0>, + <&tlmm 59 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG0"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_rear_ultra: qcom,eeprom@3 { + cell-index = <3>; + reg = <0x3>; + //qcom,eeprom-name = "semco_imx481_gt24p64b"; + compatible = "qcom,eeprom"; + qcom,slave-addr = <0xa0>; + qcom,num-blocks = <1>; + qcom,page0 = <0 0 0 0 0 0 >; + qcom,poll0 = <0 0 0 0 0 0>; + qcom,mem0 = <8192 0x0 2 0 1 0>; + qcom,cam-power-seq-type = "cam_vio"; + qcom,cam-power-seq-val = <1>; + qcom,cam-power-seq-cfg-val = <1>; + cam_vio-supply = <&camera_viodd_ldo>; + cam_vana-supply = <&pm8150l_bob>; + cam_vdig-supply = <&pm8150_l17>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk";//, "cam_bob"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 3008000 2856000 0>; + rgltr-max-voltage = <1800000 4000000 3000000 0>; + rgltr-load-current = <180000 2000000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_iris>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_iris>; + gpios = <&tlmm 13 0>,//mclk + <&tlmm 28 0>,//reset + <&tlmm 94 0>;//vana,vdig + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_VDIG3"; + sensor-position = <0>; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + eeprom_front: qcom,eeprom@2 { + cell-index = <2>; + reg = <0x2>; + compatible = "qcom,eeprom"; + cam_vio-supply = <&camera_viodd_ldo>; + cam_vana-supply = <&pm8150l_bob>; + cam_vdig-supply = <&pm8150_l17>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk";//, "cam_bob"; + rgltr-cntrl-support; + rgltr-min-voltage = <1800000 3008000 3000000 0>; + rgltr-max-voltage = <1800000 4000000 3000000 0>; + rgltr-load-current = <180000 2000000 30000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>,//mclk + <&tlmm 54 0>,//reset + //<&tlmm 132 0>,//vio + <&tlmm 118 0>;//vana,vidg + gpio-reset = <1>; + gpio-req-tbl-num = <0 1>; + gpio-req-tbl-flags = <1 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2"; + sensor-position = <1>; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + qcom,cam-sensor@0 { + cell-index = <0>; + compatible = "qcom,cam-sensor"; + reg = <0x0>; + csiphy-sd-index = <1>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + led-flash-src = <&led_flash_rear>; + actuator-src = <&actuator_rear>; + eeprom-src = <&eeprom_rear>; + cam_vio-supply = <&camera_viodd_ldo>; + cam_vana-supply = <&pm8150_s5>; + cam_vdig-supply = <&pm8150_l17>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 1904000 2856000 0>; + rgltr-max-voltage = <1800000 2040000 3008000 0>; + rgltr-load-current = <180000 112000 519000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk1_active + &cam_sensor_active_rear>; + pinctrl-1 = <&cam_sensor_mclk1_suspend + &cam_sensor_suspend_rear>; + gpios = <&tlmm 14 0>, + <&tlmm 30 0>, + <&tlmm 59 0>; + gpio-reset = <1>; + gpio-vdig = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK0", + "CAM_RESET0", + "CAM_VDIG0"; + sensor-mode = <0>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK1_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + + qcom,cam-sensor@1 { + cell-index = <1>; + compatible = "qcom,cam-sensor"; + reg = <0x1>; + csiphy-sd-index = <3>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_rear_aux>; + led-flash-src = <&led_flash_rear_aux1>; + eeprom-src = <&eeprom_rear_aux>; + cam_vio-supply = <&camera_viodd_ldo>; + cam_vdig-supply = <&pm8150_l17>; + cam_vana-supply = <&pm8150l_bob>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk";//, "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 3008000 3000000 0>; + rgltr-max-voltage = <1800000 4000000 3000000 0>; + rgltr-load-current = <180000 2000000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk3_active + &cam_sensor_active_rear_aux>; + pinctrl-1 = <&cam_sensor_mclk3_suspend + &cam_sensor_suspend_rear_aux>; + gpios = <&tlmm 16 0>,//mclk + <&tlmm 23 0>,//reset + <&tlmm 29 0>;//vana,vdig + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK1", + "CAM_RESET1", + "CAM_VANA1"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK3_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + + + qcom,cam-sensor@2 { + cell-index = <2>; + compatible = "qcom,cam-sensor"; + reg = <0x02>; + csiphy-sd-index = <2>; + sensor-position-roll = <270>; + sensor-position-pitch = <0>; + sensor-position-yaw = <0>; + eeprom-src = <&eeprom_front>; + actuator-src = <&actuator_front>; + //led-flash-src = <&led_flash_front>; + cam_vio-supply = <&camera_viodd_ldo>; + //cam_bob-supply = <&pm8150l_bob>; + cam_vana-supply = <&pm8150l_bob>; + cam_vdig-supply = <&pm8150_l17>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk";//, "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 3008000 3000000 0>; + rgltr-max-voltage = <1800000 4000000 3000000 0>; + rgltr-load-current = <180000 2000000 30000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk2_active + &cam_sensor_active_front>; + pinctrl-1 = <&cam_sensor_mclk2_suspend + &cam_sensor_suspend_front>; + gpios = <&tlmm 15 0>,//mclk + <&tlmm 54 0>,//reset + //<&tlmm 132 0>,//vio + <&tlmm 118 0>;//vana,vidg + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK2", + "CAM_RESET2", + "CAM_VANA2"; + sensor-mode = <0>; + cci-device = <1>; + cci-master = <1>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK2_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; + +qcom,cam-sensor@3 { + cell-index = <3>; + compatible = "qcom,cam-sensor"; + reg = <0x03>; + csiphy-sd-index = <0>; + sensor-position-roll = <90>; + sensor-position-pitch = <0>; + sensor-position-yaw = <180>; + actuator-src = <&actuator_ultra_rear>; + eeprom-src = <&eeprom_rear_ultra>; + led-flash-src = <&led_flash_rear_aux2>; + cam_vio-supply = <&camera_viodd_ldo>; + //cam_bob-supply = <&pm8150l_bob>; + cam_vana-supply = <&pm8150l_bob>; + cam_vdig-supply = <&pm8150_l17>; + cam_clk-supply = <&titan_top_gdsc>; + regulator-names = "cam_vio", "cam_vana", "cam_vdig", + "cam_clk";//, "cam_bob"; + rgltr-cntrl-support; + pwm-switch; + rgltr-min-voltage = <1800000 3008000 2856000 0>; + rgltr-max-voltage = <1800000 4000000 3000000 0>; + rgltr-load-current = <180000 2000000 300000 0>; + gpio-no-mux = <0>; + pinctrl-names = "cam_default", "cam_suspend"; + pinctrl-0 = <&cam_sensor_mclk0_active + &cam_sensor_active_iris>; + pinctrl-1 = <&cam_sensor_mclk0_suspend + &cam_sensor_suspend_iris>; + gpios = <&tlmm 13 0>,//mclk + <&tlmm 28 0>,//reset + <&tlmm 94 0>;//vana,vdig + gpio-reset = <1>; + gpio-vana = <2>; + gpio-req-tbl-num = <0 1 2>; + gpio-req-tbl-flags = <1 0 0>; + gpio-req-tbl-label = "CAMIF_MCLK3", + "CAM_RESET3", + "CAM_VDIG3"; + sensor-mode = <0>; + cci-device = <0>; + cci-master = <0>; + status = "ok"; + clocks = <&clock_camcc CAM_CC_MCLK0_CLK>; + clock-names = "cam_clk"; + clock-cntl-level = "turbo"; + clock-rates = <19200000>; + }; +}; + + diff --git a/arch/arm64/boot/dts/qcom/cepheus-sm8150-overlay.dts b/arch/arm64/boot/dts/qcom/cepheus-sm8150-overlay.dts new file mode 100644 index 000000000000..61e6a61fa765 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/cepheus-sm8150-overlay.dts @@ -0,0 +1,28 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/dts-v1/; +/plugin/; + +#include +#include +#include +#include + +#include "cepheus-sm8150.dtsi" +#include "cepheus-audio-overlay.dtsi" + +/ { + model = "CEPHEUS"; + compatible = "qcom,sm8150-cdp", "qcom,sm8150", "qcom,cdp"; + qcom,board-id = <37 0>; +}; diff --git a/arch/arm64/boot/dts/qcom/cepheus-sm8150.dtsi b/arch/arm64/boot/dts/qcom/cepheus-sm8150.dtsi new file mode 100644 index 000000000000..d797f673dbf3 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/cepheus-sm8150.dtsi @@ -0,0 +1,628 @@ +/* +this file is for attribution only of cepheus +And public attribution of xiaomi platforms(like F1 and so and) +*/ +#include "cepheus-pinctrl.dtsi" +#include "xiaomi-sm8150-common.dtsi" +#include "cepheus-sm8150-camera-sensor-mtp.dtsi" + +&qupv3_se4_i2c { +#include "smb1390.dtsi" +}; + +&vendor { + mtp_batterydata: qcom,battery-data { + qcom,batt-id-range-pct = <15>; + #include "batterydata-F1-atl-3300mah.dtsi" + #include "batterydata-F1-coslight-3300mah.dtsi" + #include "fg-gen4-batterydata-alium-3600mah.dtsi" + }; +}; + +&pm8150b_fg { + qcom,battery-data = <&mtp_batterydata>; + qcom,rapid-soc-dec-en; + qcom,fg-sys-term-current = <(-400)>; + qcom,fg-cutoff-voltage = <3400>; + qcom,fg-cutoff-current = <200>; + qcom,fg-empty-voltage = <3100>; + qcom,fg-batt-temp-delta = <6>; + qcom,fg-force-load-profile; + /* ESR fast calibration */ + qcom,fg-esr-timer-chg-fast = <0 7>; + qcom,fg-esr-timer-dischg-fast = <0 7>; + qcom,fg-esr-timer-chg-slow = <0 96>; + qcom,fg-esr-timer-dischg-slow = <0 96>; + qcom,fg-esr-cal-soc-thresh = <26 230>; + qcom,fg-esr-cal-temp-thresh = <10 40>; +}; + +&pm8150b_charger { + qcom,sec-charger-config = <1>; + qcom,usb-icl-ua = <2800000>; + qcom,fcc-max-ua = <4800000>; + qcom,fv-max-uv = <4400000>; + qcom,dc-icl-ua = <1000000>; + qcom,auto-recharge-soc = <99>; + qcom,chg-term-src = <1>; + qcom,chg-term-current-ma = <(-220)>; + qcom,thermal-mitigation = <3000000 2800000 2600000 2400000 2200000 2100000 2000000 + 1800000 1600000 1500000 1400000 1200000 1000000 900000 + 800000 500000>; + qcom,thermal-mitigation-icl + = <2800000 2700000 2600000 2400000 2400000 2400000 2400000 + 2400000 2400000 2100000 1900000 1700000 1500000 1300000 + 1000000 750000>; + qcom,thermal-mitigation-dcp + = <1800000 1800000 1800000 1800000 1800000 1800000 1800000 + 1800000 1800000 1700000 1600000 1400000 1200000 1100000 + 1100000 1000000>; + qcom,thermal-mitigation-qc2 + = <1500000 1500000 1500000 1500000 1450000 1400000 1350000 + 1300000 1300000 1200000 1000000 900000 850000 750000 + 650000 500000>; + qcom,thermal-fcc-qc3-normal + = <3200000 3000000 2800000 2600000 2500000 2400000 2300000 + 2200000 2100000 1800000 1600000 1400000 1200000 1000000 + 750000 750000>; + qcom,thermal-fcc-qc3-cp + = <3600000 3600000 3600000 3600000 3200000 3200000 3200000 + 3200000 3100000 2800000 2400000 2200000 2000000 1300000 + 750000 700000>; + qcom,thermal-fcc-qc3-classb-cp + = <4800000 4700000 4600000 4500000 4400000 4200000 4200000 + 4200000 4000000 3600000 3400000 3200000 3000000 2200000 + 1000000 700000>; + qcom,thermal-mitigation-pd-base + = <3000000 2800000 2600000 2500000 2500000 2500000 2500000 + 2500000 2500000 2400000 2200000 2000000 1600000 1300000 + 1000000 500000>; + qcom,thermal-fcc-pps-cp + = <4800000 4700000 4600000 4500000 4400000 4200000 4200000 + 4200000 4000000 3600000 3400000 3200000 3000000 2200000 + 1000000 750000>; + qcom,thermal-mitigation-dc + = <2100000 2000000 1800000 1600000 1400000 1200000 1100000 + 1000000 900000 800000 700000 600000 500000 400000 + 300000 200000>; + qcom,thermal-mitigation-epp + = <1200000 1200000 1200000 1100000 1100000 1000000 1000000 + 1000000 900000 700000 700000 600000 500000 400000 + 300000 200000>; + qcom,thermal-mitigation-bpp-qc3 + = <1400000 1300000 1200000 1200000 1100000 1000000 900000 + 800000 700000 700000 700000 600000 500000 400000 + 300000 200000>; + qcom,thermal-mitigation-bpp-qc2 + = <1100000 1100000 1100000 1100000 1100000 1000000 1000000 + 1000000 700000 700000 700000 600000 500000 400000 + 300000 200000>; + qcom,thermal-mitigation-bpp + = <800000 800000 800000 800000 800000 800000 800000 + 800000 800000 700000 700000 600000 500000 400000 + 300000 200000>; + + io-channels = <&pm8150b_vadc ADC_MID_CHG_DIV6>, + <&pm8150b_vadc ADC_USB_IN_V_16>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_SBUx>, + <&pm8150b_vadc ADC_VPH_PWR>, + <&pm8150b_vadc ADC_CHG_TEMP>; + + io-channel-names = "mid_voltage", + "usb_in_voltage", + "usb_in_current", + "sbux_res", + "vph_voltage", + "chg_temp"; + + qcom,battery-data = <&mtp_batterydata>; + dpdm-supply = <&usb2_phy0>; + qcom,distinguish-qc-class-ab; + qcom,sw-jeita-enable; + qcom,wd-bark-time-secs = <16>; + qcom,support-wireless; + qcom,dynamic-fv-enable; + qcom,lpd-disable; +}; + +&ext_5v_boost { + status = "ok"; +}; + +&pm8150b_pdphy { + vbus-supply = <&ext_5v_boost>; +}; + +&qupv3_se4_i2c { + status = "ok"; + tas2557@4c { + compatible = "ti,tas2557"; + reg = <0x4c>; + //ti,cdc-reset-gpio = <&tlmm 59 0>; + ti,irq-gpio = <&tlmm 60 0>; + ti,i2s-bits = <16>; + ti,bypass-tmax = <0>; + }; + + fsa4480@42 { + status = "disabled"; + }; + + cs35l41@40 { + #sound-dai-cells = <1>; + compatible = "cirrus,cs35l41"; + cs,cdc-reset-gpio = <&tlmm 89 0x01>; + reg = <0x40>; + pinctrl-names = "cs35l41_irq_default"; + pinctrl-0 = <&cs35l41_int_default>; + interrupt-parent = <&tlmm>; + interrupts = <10 8>; + + cirrus,temp-warn_threshold = <3>; + cirrus,boost-peak-milliamp = <4000>; + cirrus,boost-ind-nanohenry = <1000>; + cirrus,boost-cap-microfarad = <15>; + cirrus,gpio-config2 { + cirrus,gpio-src-select = <0x4>; + cirrus,gpio-output-enable; + }; + }; + +}; + +&smb1390 { + pinctrl-names = "default"; + pinctrl-0 = <&smb_stat_default>; + status = "ok"; +}; + +&smb1390_charger { + io-channels = <&pm8150b_vadc ADC_AMUX_THM2>; + io-channel-names = "cp_die_temp"; + status = "ok"; +}; + +&usb2_phy0 { + qcom,param-override-seq = + <0x84 0x70 + 0x2c 0x74>; +}; + +&usb_qmp_dp_phy { + status = "disabled"; +}; + +&usb0 { + dwc3@a600000 { + usb-phy = <&usb2_phy0>, <&usb_nop_phy>; + maximum-speed = "high-speed"; + }; +}; + +&soc { + touch_vddio_vreg: touch_vddio_vreg { + compatible = "regulator-fixed"; + regulator-name = "disp_vddio_vreg"; + startup-delay-us = <4000>; + enable-active-high; + regulator-boot-on; + gpio = <&tlmm 84 0>; + }; + + vdd_boost_vreg: vdd_boost_vreg { + compatible = "regulator-fixed"; + regulator-name = "vdd_boost_vreg"; + startup-delay-us = <4000>; + enable-active-high; + regulator-always-on; + gpio = <&pm8150b_gpios 5 0>; + }; + + disp_vci_vreg: disp_vci_vreg { + compatible = "regulator-fixed"; + regulator-name = "disp_vci_vreg"; + start-delay-us = <4000>; + enable-active-high; + regulator-boot-on; + gpio = <&tlmm 21 0>; + }; + + dsi_amoled_panel_pwr_external_supply: dsi_amoled_panel_pwr_external_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + //qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vcie"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <10>; + qcom,supply-pre-off-sleep = <10>; + }; + }; + + fingerprint_goodix { + compatible = "goodix,fingerprint"; + goodix,gpio-reset = <&tlmm 37 0x0>; + goodix,gpio-irq = <&tlmm 120 0x0>; + fp-gpio-pwr = <&tlmm 125 0>; + status = "ok"; + }; + + gpio_keys { + pinctrl-0 = <&ai_key_active_default>; + ai_key { + label = "ai_key"; + gpios = <&tlmm 97 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <39>; + gpio-key,level-trigger; + }; + }; +}; + +&qupv3_se17_i2c { + status = "ok"; + fts@49 { + compatible = "st,fts"; + reg = <0x49>; + interrupt-parent = <&tlmm>; + interrupts = <122 0x2008>; + pinctrl-names = "pmx_ts_active", "pmx_ts_suspend"; + pinctrl-0 = <&ts_active>; + pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; + vdd-supply = <&touch_vddio_vreg>; + avdd-supply = <&pm8150l_l1>; + fts,pwr-reg-name = "avdd"; + fts,bus-reg-name = "vdd"; + fts,irq-gpio = <&tlmm 122 0x2008>; + fts,irq-gpio-name = "fts_irq"; + fts,reset-gpio-enable; + fts,reset-gpio = <&tlmm 12 0x00>; + fts,reset-gpio-name = "fts_rst"; + fts,irq-flags = <0x2008>; /* IRQF_ONESHOT | IRQF_TRIGGER_LOW */ + fts,x-max = <1080>; + fts,y-max = <2340>; + fts,default-fw-name = "st_fts_f1.ftb"; + fts,config-array-size = <1>; + fts,cfg_0 { + fts,tp-vendor = <0x48>; + fts,fw-name = "st_fts_f1.ftb"; + fts,limit-name = "stm_fts_production_limits.csv"; + fts,clicknum-file-name = "fts+sdc"; + }; + }; +}; + +&qupv3_se4_i2c { + status = "ok"; + idtp9220: idtp9220@3b { + compatible = "idt,p9220"; + reg = <0x3b>; + idt,irq = <&tlmm 90 0x00>; + idt,enable = <&tlmm 104 0x00>; + idt,wpc-det = <&pm8150b_gpios 7 GPIO_ACTIVE_HIGH>; + pinctrl-names = "default", "idt_active", "idt_suspend"; + pinctrl-0 = <&power_good_default>; + pinctrl-1 = <&idt_int_active &idt_enable_active>; + pinctrl-2 = <&idt_int_suspend &idt_enable_suspend>; + }; +}; + + +&qupv3_se1_spi { + status = "ok"; + irled@0 { + compatible = "ir-spi"; + reg = <0x0>; + status = "ok"; + spi-max-frequency = <19200000>; + }; +}; + +&pm8150l_lpg { + qcom,lut-patterns = <0 1 2 3 4 5 7 9 11 13 15 + 13 11 9 7 5 4 3 2 1 0>; +}; + +&red_led { + label = "white"; +}; + +&green_led { + status = "disabled"; +}; + +&blue_led { + status = "disabled"; +}; + +&sde_dsi { + vcie-supply = <&disp_vci_vreg>; +}; + +&dsi_samsung_fhd_ea8076_f1mp_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_external_supply>; +}; + +&dsi_samsung_fhd_ea8076_f1p2_2_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_external_supply>; +}; + +&dsi_samsung_fhd_ea8076_f1p2_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_external_supply>; +}; + +&dsi_ss_fhd_ea8076_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_external_supply>; +}; + +&dsi_ss_fhd_ea8076_global_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_external_supply>; +}; + +&pm8150b_vadc { + vph_pwr { + reg = ; + label = "vph_pwr"; + qcom,pre-scaling = <1 3>; + }; + + vcoin { + reg = ; + label = "vcoin"; + qcom,pre-scaling = <1 3>; + }; + + conn_therm { + reg = ; + label = "conn_therm"; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + qcom,pre-scaling = <1 1>; + }; + + chg_sbux { + reg = ; + label = "chg_sbux"; + qcom,pre-scaling = <1 3>; + }; + + mid_chg_div6 { + reg = ; + label = "chg_mid"; + qcom,pre-scaling = <1 6>; + }; + + usb_in_i_uv { + reg = ; + label = "usb_in_i_uv"; + qcom,pre-scaling = <1 1>; + }; + + usb_in_v_div_16 { + reg = ; + label = "usb_in_v_div_16"; + qcom,pre-scaling = <1 16>; + }; +}; + +&pm8150b_adc_tm { + wp_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150_adc_tm { + xo_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + quiet_therm { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm0 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&pm8150l_adc_tm { + cam_therm0 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + cam_therm1 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; + + pa_therm1 { + reg = ; + qcom,ratiometric; + qcom,hw-settle-time = <200>; + }; +}; + +&thermal_zones { + wp_therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150b_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + xo_therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_XO_THERM_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + quiet_therm { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa_therm0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cam_therm0 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM1_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + cam_therm1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM2_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; + + pa_therm1 { + polling-delay-passive = <0>; + polling-delay = <0>; + thermal-governor = "user_space"; + thermal-sensors = <&pm8150l_adc_tm ADC_AMUX_THM3_PU2>; + trips { + active-config0 { + temperature = <125000>; + hysteresis = <1000>; + type = "passive"; + }; + }; + }; +}; + +&pm8150b_haptics { + qcom,vmax-mv = <2800>; + qcom,play-rate-us = <5102>; + + wf_0 { + /* CLICK */ + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e]; + qcom,wf-brake-pattern = [02 01 00 00]; + qcom,wf-play-rate-us = <5102>; + }; + wf_1 { + /* DOUBLE CLICK */ + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 3e]; + qcom,wf-brake-pattern = [03 01 01 00]; + qcom,wf-play-rate-us = <5102>; + }; + wf_2 { + /* TICK */ + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 3e]; + qcom,wf-brake-pattern = [03 01 01 00]; + qcom,wf-play-rate-us = <5102>; + }; + wf_3 { + /* THUD */ + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e]; + qcom,wf-brake-pattern = [02 01 00 00]; + qcom,wf-play-rate-us = <5102>; + }; + wf_4 { + /* POP */ + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [3e 3e]; + qcom,wf-brake-pattern = [02 01 00 00]; + qcom,wf-play-rate-us = <5102>; + }; + wf_5 { + /* HEAVY CLICK */ + qcom,wf-vmax-mv = <3600>; + qcom,wf-pattern = [7e 7e 7e]; + qcom,wf-brake-pattern = [03 03 01 00]; + qcom,wf-play-rate-us = <5102>; + }; +}; + +&ssc_sensors { + qcom,firmware-name = "slpi_cp"; +}; + +&mdss_dsi_phy0 { + qcom,panel-allow-phy-poweroff; + qcom,dsi-phy-regulator-min-datarate-bps = <1200000000>; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-cmd.dtsi new file mode 100644 index 000000000000..b81c37437599 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-cmd.dtsi @@ -0,0 +1,253 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&soc { + dsi_samsung_fhd_ea8076_cmd: qcom,mdss_dsi_samsung_fhd_ea8076_cmd { + qcom,mdss-dsi-panel-name = "samsung ea8076 fhd cmd dsi panel"; + qcom,mdss-dsi-panel-id = <0>; + qcom,mdss-dsi-panel-model = "SAMSUNG FHD EA8076 CMD PANEL"; + qcom,mdss-dsi-panel-sleepwrmod = <0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,ulps-enabled; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-brightness-max-level = <2047>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-dcs-type-ss; + qcom,mdss-dsi-reset-sequence = <0 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <147>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4300000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dispparam-enabled; + qcom,mdss-panel-on-dimming-delay = <120>; + qcom,disp-doze-lpm-backlight = <20>; + qcom,disp-doze-hbm-backlight = <266>; + /* IRQF_ONESHOT | IRQF_TRIGGER_FALLING */ + qcom,esd-err-irq-gpio = <&tlmm 27 0x2002>; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <64>; + qcom,mdss-dsi-v-front-porch = <64>; + qcom,mdss-dsi-v-pulse-width = <20>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + qcom,mdss-dsi-panel-jitter = <0x5 0x1>; + qcom,mdss-dsi-on-command = [ + /* delay 2ms for VCI1 power */ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 FF 10 + 39 00 00 00 00 00 02 B0 2F + 39 00 00 00 00 00 02 D1 01 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 03 FC A5 A5 + /* Sleep Out */ + 05 01 00 00 0A 00 02 11 00 + 39 00 00 00 00 00 03 F0 5A 5A + /* TE OUT(Vsync On) */ + 39 00 00 00 00 00 02 35 00 + /* DBV Smooth Transition */ + 39 00 00 00 00 00 03 B7 01 4B + /* Timing set */ + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 03 D9 88 2E + /* Edge Dimming */ + 39 00 00 00 00 00 02 B0 09 + 39 00 00 00 00 00 02 D8 00 + 39 01 00 00 00 00 03 F0 A5 A5 + /* Page Address Set */ + 39 01 00 00 00 00 05 2B 00 00 09 23 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + /* ERR_FG Setting */ + 39 00 00 00 00 00 07 E1 00 00 02 02 42 02 + 39 00 00 00 00 00 07 E2 00 00 00 00 00 00 + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 E1 19 + /* OFC Setting 82.6Mhz*/ + 39 00 00 00 00 00 0C E9 11 55 A6 75 A3 B8 BB 2A 00 1A B8 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + /* Brightness Control */ + 39 00 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 51 00 00 + 39 01 00 00 43 00 02 55 00 + /* Display On */ + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-doze-hbm-command = [ + /* AOD ON Sequence (Normal To AOD HBM) */ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 00 00 00 01 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-doze-lbm-command = [ + /* AOD ON Sequence (Normal To AOD LBM) */ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 00 00 00 00 00 02 53 23 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-nolp-command = [ + /* AOD OFF Sequence (AOD To Normal) */ + 05 01 00 00 22 00 02 28 00 + 39 01 00 00 00 00 02 53 20 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-doze-hbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-doze-lbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-acl-off-command = [39 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-dispparam-acl-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l1-command = [39 01 00 00 00 00 02 55 01];/* 50% */ + qcom,mdss-dsi-dispparam-acl-l1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l2-command = [39 01 00 00 00 00 02 55 02];/* 40% */ + qcom,mdss-dsi-dispparam-acl-l2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l3-command = [39 01 00 00 00 00 02 55 03];/* 30% */ + qcom,mdss-dsi-dispparam-acl-l3-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-hbm-off-command = [39 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-dispparam-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-on-command = [39 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-dispparam-hbm-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-off-command = [ + 39 01 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 49 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 C9 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 02 53 E0 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 43 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-fod2norm-command = [39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B2 00 40 + 39 00 00 00 00 00 02 B0 04 + 39 00 00 00 00 00 02 B2 80 + 39 00 00 00 00 00 02 F7 03 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod2norm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingon-command = [39 01 00 00 01 00 02 53 28]; + qcom,mdss-dsi-dispparam-dimmingon-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingoff-command = [39 01 00 00 01 00 02 53 20]; + qcom,mdss-dsi-dispparam-dimmingoff-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-srgb-on-command = [ + /* CRC Enable + sRGB mode */ + 39 01 00 00 00 00 02 81 90 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 BD 02 00 14 D1 00 04 07 AA 0C EC CB C8 0F DD D9 E4 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command = [ + /* CRC Enable + DCI-P3 mode */ + 39 01 00 00 00 00 02 81 91 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 CB 0B 01 0B EC 03 05 08 CF 14 FA FA E7 05 EE EE F2 00 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-off-command = [ + /* CRC Disable (Normal mode) */ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Bypass */ + 39 01 00 00 00 00 02 B1 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-h-sync-pulse = <0>; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1-cmd.dtsi new file mode 100644 index 000000000000..49255e3b4d09 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1-cmd.dtsi @@ -0,0 +1,255 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&soc { + dsi_samsung_fhd_ea8076_f1_cmd: qcom,mdss_dsi_samsung_fhd_ea8076_f1_cmd { + qcom,mdss-dsi-panel-name = "samsung ea8076 fhd cmd dsi panel"; + qcom,mdss-dsi-panel-id = <0>; + qcom,mdss-dsi-panel-model = "SAMSUNG FHD EA8076 CMD PANEL"; + qcom,mdss-dsi-panel-sleepwrmod = <0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,ulps-enabled; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-brightness-max-level = <2047>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-dcs-type-ss; + qcom,mdss-dsi-reset-sequence = <0 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <147>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4300000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dispparam-enabled; + qcom,mdss-panel-on-dimming-delay = <200>; + /* IRQF_ONESHOT | IRQF_TRIGGER_FALLING */ + qcom,esd-err-irq-gpio = <&tlmm 5 0x2002>; + + qcom,disp-doze-lpm-backlight = <20>; + qcom,disp-doze-hbm-backlight = <266>; + qcom,disp-fod-off-dimming-delay = <85>; + + qcom,elvss_dimming_check_enable; + qcom,mdss-dsi-panel-elvss-dimming-read-length = <1>; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command = [39 01 00 00 00 00 02 B0 07]; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command = [06 01 00 01 00 00 01 B7]; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <64>; + qcom,mdss-dsi-v-front-porch = <64>; + qcom,mdss-dsi-v-pulse-width = <20>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + qcom,mdss-dsi-panel-jitter = <0x5 0x1>; + qcom,mdss-dsi-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 FF 10 + 39 00 00 00 00 00 02 B0 2F + 39 01 00 00 00 00 02 D1 01 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 05 01 00 00 0A 00 02 11 00 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 35 00 + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 06 + 39 00 00 00 00 00 02 B7 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 05 2B 00 00 09 23 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 23 + 39 00 00 00 00 00 02 D1 33 + 39 00 00 00 00 00 0C E9 11 55 A6 75 A3 A6 37 BE 00 1A B8 + 39 00 00 00 00 00 0C D9 14 00 00 8F 6E 00 00 8F 2E 6E 34 + 39 00 00 00 00 00 6D C0 31 01 03 00 06 00 00 00 00 00 00 00 00 00 00 00 00 50 00 00 40 3D 00 5E 00 00 00 20 07 20 30 58 00 00 00 00 00 00 E0 0B 75 D8 00 00 00 00 FC 00 00 00 F6 97 0F 6D E6 CD 05 21 8B EC ED ED ED 0D 3F 60 00 67 FD 6D 51 BC DD DD 00 00 07 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 70 2F 00 00 03 2E 3C 20 E0 00 00 00 00 00 06 8C + 39 01 00 00 00 00 02 C0 31 + 39 00 00 00 00 00 07 E1 00 00 02 02 42 02 + 39 00 00 00 00 00 07 E2 00 00 00 00 00 00 + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 E1 19 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 39 00 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 51 00 00 + 39 01 00 00 43 00 02 55 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-doze-hbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 01 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-doze-lbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 00 00 02 53 23 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 22 00 02 28 00 + 39 01 00 00 00 00 02 53 20 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-doze-hbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-doze-lbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-acl-off-command = [39 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-dispparam-acl-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l1-command = [39 01 00 00 00 00 02 55 01];/* 50% */ + qcom,mdss-dsi-dispparam-acl-l1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l2-command = [39 01 00 00 00 00 02 55 02];/* 40% */ + qcom,mdss-dsi-dispparam-acl-l2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l3-command = [39 01 00 00 00 00 02 55 03];/* 30% */ + qcom,mdss-dsi-dispparam-acl-l3-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-hbm-off-command = [39 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-dispparam-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-on-command = [39 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-dispparam-hbm-on-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-dimmingon-command = [39 01 00 00 01 00 02 53 28]; + qcom,mdss-dsi-dispparam-dimmingon-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingoff-command = [39 01 00 00 01 00 02 53 20]; + qcom,mdss-dsi-dispparam-dimmingoff-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-srgb-on-command = [ + /* CRC Enable + sRGB mode */ + 39 01 00 00 00 00 02 81 90 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 BD 02 00 14 D1 00 04 07 AA 0C EC CB C8 0F DD D9 E4 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command = [ + /* CRC Enable + DCI-P3 mode */ + 39 01 00 00 00 00 02 81 91 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 CB 0B 01 0B EC 03 05 08 CF 14 FA FA E7 05 EE EE F2 00 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-off-command = [ + /* CRC Disable (Normal mode) */ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Bypass */ + 39 01 00 00 00 00 02 B1 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + + qcom,mdss-dsi-dispparam-hbm-fod-off-command = [ + 39 01 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 49 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 C9 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 11 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 02 53 E0 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 43 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-on-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1mp-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1mp-cmd.dtsi new file mode 100644 index 000000000000..511b6217477a --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1mp-cmd.dtsi @@ -0,0 +1,255 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&soc { + dsi_samsung_fhd_ea8076_f1mp_cmd: qcom,mdss_dsi_samsung_fhd_ea8076_f1mp_cmd { + qcom,mdss-dsi-panel-name = "samsung ea8076 fhd cmd dsi panel"; + qcom,mdss-dsi-panel-id = <0>; + qcom,mdss-dsi-panel-model = "SAMSUNG FHD EA8076 CMD PANEL"; + qcom,mdss-dsi-panel-sleepwrmod = <0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,ulps-enabled; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-brightness-max-level = <2047>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-dcs-type-ss; + qcom,mdss-dsi-reset-sequence = <0 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <147>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4300000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dispparam-enabled; + qcom,mdss-panel-on-dimming-delay = <200>; + /* IRQF_ONESHOT | IRQF_TRIGGER_FALLING */ + qcom,esd-err-irq-gpio = <&tlmm 5 0x2002>; + + qcom,disp-doze-lpm-backlight = <20>; + qcom,disp-doze-hbm-backlight = <266>; + qcom,disp-fod-off-dimming-delay = <85>; + + qcom,elvss_dimming_check_enable; + qcom,mdss-dsi-panel-elvss-dimming-read-length = <1>; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command = [39 01 00 00 00 00 02 B0 07]; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command = [06 01 00 01 00 00 01 B7]; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <64>; + qcom,mdss-dsi-v-front-porch = <64>; + qcom,mdss-dsi-v-pulse-width = <20>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + qcom,mdss-dsi-panel-jitter = <0x5 0x1>; + qcom,mdss-dsi-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 FF 10 + 39 00 00 00 00 00 02 B0 2F + 39 01 00 00 00 00 02 D1 01 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 05 01 00 00 0A 00 02 11 00 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 35 00 + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 06 + 39 00 00 00 00 00 02 B7 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 05 2B 00 00 09 23 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 23 + 39 00 00 00 00 00 02 D1 33 + 39 00 00 00 00 00 0C E9 11 55 A6 75 A3 A6 37 BE 00 1A B8 + 39 00 00 00 00 00 0C D9 14 00 00 8F 6E 00 00 8F 2E 6E 34 + 39 00 00 00 00 00 6D C0 31 01 03 00 06 00 00 00 00 00 00 00 00 00 00 00 00 50 00 00 40 3D 00 5E 00 00 00 20 07 20 30 58 00 00 00 00 00 00 E0 0B 75 D8 00 00 00 00 FC 00 00 00 F6 97 0F 6D E6 CD 05 21 8B EC ED ED ED 0D 3F 60 00 67 FD 6D 51 BC DD DD 00 00 07 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 70 2F 00 00 03 2E 3C 20 E0 00 00 00 00 00 06 8C + 39 01 00 00 00 00 02 C0 31 + 39 00 00 00 00 00 07 E1 00 00 02 02 42 02 + 39 00 00 00 00 00 07 E2 00 00 00 00 00 00 + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 E1 19 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 39 00 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 51 00 00 + 39 01 00 00 43 00 02 55 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-doze-hbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 01 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-doze-lbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 00 00 02 53 23 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 22 00 02 28 00 + 39 01 00 00 00 00 02 53 20 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-doze-hbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-doze-lbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-acl-off-command = [39 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-dispparam-acl-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l1-command = [39 01 00 00 00 00 02 55 01];/* 50% */ + qcom,mdss-dsi-dispparam-acl-l1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l2-command = [39 01 00 00 00 00 02 55 02];/* 40% */ + qcom,mdss-dsi-dispparam-acl-l2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l3-command = [39 01 00 00 00 00 02 55 03];/* 30% */ + qcom,mdss-dsi-dispparam-acl-l3-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-hbm-off-command = [39 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-dispparam-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-on-command = [39 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-dispparam-hbm-on-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-dimmingon-command = [39 01 00 00 01 00 02 53 28]; + qcom,mdss-dsi-dispparam-dimmingon-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingoff-command = [39 01 00 00 01 00 02 53 20]; + qcom,mdss-dsi-dispparam-dimmingoff-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-srgb-on-command = [ + /* CRC Enable + sRGB mode */ + 39 01 00 00 00 00 02 81 90 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 BD 02 00 14 D1 00 04 07 AA 0C EC CB C8 0F DD D9 E4 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command = [ + /* CRC Enable + DCI-P3 mode */ + 39 01 00 00 00 00 02 81 91 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 CB 0B 01 0B EC 03 05 08 CF 14 FA FA E7 05 EE EE F2 00 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-off-command = [ + /* CRC Disable (Normal mode) */ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Bypass */ + 39 01 00 00 00 00 02 B1 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + + qcom,mdss-dsi-dispparam-hbm-fod-off-command = [ + 39 01 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 49 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 C9 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 11 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 02 53 E0 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 43 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-on-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1p2-2-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1p2-2-cmd.dtsi new file mode 100644 index 000000000000..ffd9788b5a8e --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1p2-2-cmd.dtsi @@ -0,0 +1,255 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&soc { + dsi_samsung_fhd_ea8076_f1p2_2_cmd: qcom,mdss_dsi_samsung_fhd_ea8076_f1p2_2_cmd { + qcom,mdss-dsi-panel-name = "samsung ea8076 fhd cmd dsi panel"; + qcom,mdss-dsi-panel-id = <0>; + qcom,mdss-dsi-panel-model = "SAMSUNG FHD EA8076 CMD PANEL"; + qcom,mdss-dsi-panel-sleepwrmod = <0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,ulps-enabled; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-brightness-max-level = <2047>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-dcs-type-ss; + qcom,mdss-dsi-reset-sequence = <0 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <147>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4300000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dispparam-enabled; + qcom,mdss-panel-on-dimming-delay = <200>; + /* IRQF_ONESHOT | IRQF_TRIGGER_FALLING */ + qcom,esd-err-irq-gpio = <&tlmm 5 0x2002>; + + qcom,disp-doze-lpm-backlight = <20>; + qcom,disp-doze-hbm-backlight = <266>; + qcom,disp-fod-off-dimming-delay = <85>; + + qcom,elvss_dimming_check_enable; + qcom,mdss-dsi-panel-elvss-dimming-read-length = <1>; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command = [39 01 00 00 00 00 02 B0 07]; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command = [06 01 00 01 00 00 01 B7]; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <64>; + qcom,mdss-dsi-v-front-porch = <64>; + qcom,mdss-dsi-v-pulse-width = <20>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + qcom,mdss-dsi-panel-jitter = <0x5 0x1>; + qcom,mdss-dsi-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 FF 10 + 39 00 00 00 00 00 02 B0 2F + 39 01 00 00 00 00 02 D1 01 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 05 01 00 00 0A 00 02 11 00 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 35 00 + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 06 + 39 00 00 00 00 00 02 B7 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 05 2B 00 00 09 23 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 24 + 39 00 00 00 00 00 02 D1 33 + 39 00 00 00 00 00 0C E9 11 55 A6 75 A3 A6 37 BE 00 1A B8 + 39 00 00 00 00 00 0C D9 14 00 00 8F 6E 00 00 8F 2E 6E 34 + 39 00 00 00 00 00 6D C0 31 01 03 00 06 00 00 00 00 00 00 00 00 00 00 00 00 50 00 00 40 3D 00 5E 00 00 00 20 07 20 30 58 00 00 00 00 00 00 E0 0B 75 D8 00 00 00 00 FC 00 00 00 F6 97 0F 6D E6 CD 05 21 8B EC ED ED ED 0D 3F 60 00 67 FD 6D 51 BC DD DD 00 00 07 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 70 2F 00 00 03 2E 3C 20 E0 00 00 00 00 00 06 8C + 39 01 00 00 00 00 02 C0 31 + 39 00 00 00 00 00 07 E1 00 00 02 02 42 02 + 39 00 00 00 00 00 07 E2 00 00 00 00 00 00 + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 E1 19 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 39 00 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 51 00 00 + 39 01 00 00 43 00 02 55 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-doze-hbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 01 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-doze-lbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 00 00 02 53 23 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 22 00 02 28 00 + 39 01 00 00 00 00 02 53 20 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-doze-hbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-doze-lbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-acl-off-command = [39 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-dispparam-acl-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l1-command = [39 01 00 00 00 00 02 55 01];/* 50% */ + qcom,mdss-dsi-dispparam-acl-l1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l2-command = [39 01 00 00 00 00 02 55 02];/* 40% */ + qcom,mdss-dsi-dispparam-acl-l2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l3-command = [39 01 00 00 00 00 02 55 03];/* 30% */ + qcom,mdss-dsi-dispparam-acl-l3-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-hbm-off-command = [39 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-dispparam-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-on-command = [39 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-dispparam-hbm-on-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-dimmingon-command = [39 01 00 00 01 00 02 53 28]; + qcom,mdss-dsi-dispparam-dimmingon-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingoff-command = [39 01 00 00 01 00 02 53 20]; + qcom,mdss-dsi-dispparam-dimmingoff-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-srgb-on-command = [ + /* CRC Enable + sRGB mode */ + 39 01 00 00 00 00 02 81 90 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 BD 02 00 14 D1 00 04 07 AA 0C EC CB C8 0F DD D9 E4 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command = [ + /* CRC Enable + DCI-P3 mode */ + 39 01 00 00 00 00 02 81 91 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 CB 0B 01 0B EC 03 05 08 CF 14 FA FA E7 05 EE EE F2 00 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-off-command = [ + /* CRC Disable (Normal mode) */ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Bypass */ + 39 01 00 00 00 00 02 B1 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + + qcom,mdss-dsi-dispparam-hbm-fod-off-command = [ + 39 01 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 49 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 C9 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 11 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 02 53 E0 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 43 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-on-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1p2-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1p2-cmd.dtsi new file mode 100644 index 000000000000..306ab7ca7030 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-samsung-fhd-ea8076-f1p2-cmd.dtsi @@ -0,0 +1,255 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&soc { + dsi_samsung_fhd_ea8076_f1p2_cmd: qcom,mdss_dsi_samsung_fhd_ea8076_f1p2_cmd { + qcom,mdss-dsi-panel-name = "samsung ea8076 fhd cmd dsi panel"; + qcom,mdss-dsi-panel-id = <0>; + qcom,mdss-dsi-panel-model = "SAMSUNG FHD EA8076 CMD PANEL"; + qcom,mdss-dsi-panel-sleepwrmod = <0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,ulps-enabled; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-brightness-max-level = <2047>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-dcs-type-ss; + qcom,mdss-dsi-reset-sequence = <0 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <147>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4300000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dispparam-enabled; + qcom,mdss-panel-on-dimming-delay = <200>; + /* IRQF_ONESHOT | IRQF_TRIGGER_FALLING */ + qcom,esd-err-irq-gpio = <&tlmm 5 0x2002>; + + qcom,disp-doze-lpm-backlight = <20>; + qcom,disp-doze-hbm-backlight = <266>; + qcom,disp-fod-off-dimming-delay = <85>; + + qcom,elvss_dimming_check_enable; + qcom,mdss-dsi-panel-elvss-dimming-read-length = <1>; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command = [39 01 00 00 00 00 02 B0 07]; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command = [06 01 00 01 00 00 01 B7]; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <64>; + qcom,mdss-dsi-v-front-porch = <64>; + qcom,mdss-dsi-v-pulse-width = <20>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + qcom,mdss-dsi-panel-jitter = <0x5 0x1>; + qcom,mdss-dsi-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 FF 10 + 39 00 00 00 00 00 02 B0 2F + 39 01 00 00 00 00 02 D1 01 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 05 01 00 00 0A 00 02 11 00 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 35 00 + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 06 + 39 00 00 00 00 00 02 B7 10 + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 05 2B 00 00 09 23 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 23 + 39 00 00 00 00 00 02 D1 33 + 39 00 00 00 00 00 0C E9 11 55 A6 75 A3 A6 37 BE 00 1A B8 + 39 00 00 00 00 00 0C D9 14 00 00 8F 6E 00 00 8F 2E 6E 34 + 39 00 00 00 00 00 6D C0 31 01 03 00 06 00 00 00 00 00 00 00 00 00 00 00 00 50 00 00 40 3D 00 5E 00 00 00 20 07 20 30 58 00 00 00 00 00 00 E0 0B 75 D8 00 00 00 00 FC 00 00 00 F6 97 0F 6D E6 CD 05 21 8B EC ED ED ED 0D 3F 60 00 67 FD 6D 51 BC DD DD 00 00 07 00 00 20 00 00 00 00 00 00 00 00 00 00 00 00 70 2F 00 00 03 2E 3C 20 E0 00 00 00 00 00 06 8C + 39 01 00 00 00 00 02 C0 31 + 39 00 00 00 00 00 07 E1 00 00 02 02 42 02 + 39 00 00 00 00 00 07 E2 00 00 00 00 00 00 + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 E1 19 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 39 00 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 51 00 00 + 39 01 00 00 43 00 02 55 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-doze-hbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 01 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-doze-lbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 00 00 02 53 23 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 22 00 02 28 00 + 39 01 00 00 00 00 02 53 20 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-doze-hbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-doze-lbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-acl-off-command = [39 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-dispparam-acl-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l1-command = [39 01 00 00 00 00 02 55 01];/* 50% */ + qcom,mdss-dsi-dispparam-acl-l1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l2-command = [39 01 00 00 00 00 02 55 02];/* 40% */ + qcom,mdss-dsi-dispparam-acl-l2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l3-command = [39 01 00 00 00 00 02 55 03];/* 30% */ + qcom,mdss-dsi-dispparam-acl-l3-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-hbm-off-command = [39 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-dispparam-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-on-command = [39 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-dispparam-hbm-on-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-dimmingon-command = [39 01 00 00 01 00 02 53 28]; + qcom,mdss-dsi-dispparam-dimmingon-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingoff-command = [39 01 00 00 01 00 02 53 20]; + qcom,mdss-dsi-dispparam-dimmingoff-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-srgb-on-command = [ + /* CRC Enable + sRGB mode */ + 39 01 00 00 00 00 02 81 90 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 BD 02 00 14 D1 00 04 07 AA 0C EC CB C8 0F DD D9 E4 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command = [ + /* CRC Enable + DCI-P3 mode */ + 39 01 00 00 00 00 02 81 91 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 CB 0B 01 0B EC 03 05 08 CF 14 FA FA E7 05 EE EE F2 00 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-off-command = [ + /* CRC Disable (Normal mode) */ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Bypass */ + 39 01 00 00 00 00 02 B1 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + + qcom,mdss-dsi-dispparam-hbm-fod-off-command = [ + 39 01 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 49 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 C9 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 11 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 02 53 E0 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 43 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-on-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-ss-fhd-ea8076-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-ss-fhd-ea8076-cmd.dtsi new file mode 100644 index 000000000000..33d17bbb2fc8 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-ss-fhd-ea8076-cmd.dtsi @@ -0,0 +1,244 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&soc { + dsi_ss_fhd_ea8076_cmd: qcom,mdss_dsi_ss_fhd_ea8076_cmd { + qcom,mdss-dsi-panel-name = "samsung ea8076 fhd cmd dsi panel"; + qcom,mdss-dsi-panel-id = <0>; + qcom,mdss-dsi-panel-model = "SAMSUNG FHD EA8076 CMD PANEL"; + qcom,mdss-dsi-panel-sleepwrmod = <0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,ulps-enabled; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-brightness-max-level = <2047>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-dcs-type-ss; + qcom,mdss-dsi-reset-sequence = <0 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <147>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4300000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dispparam-enabled; + qcom,mdss-panel-on-dimming-delay = <120>; + /* IRQF_ONESHOT | IRQF_TRIGGER_FALLING */ + /* trig-flags: falling-0x0002 rasing-0x0001 */ + qcom,esd-err-irq-gpio = <&tlmm 5 0x2002>; + + qcom,disp-doze-lpm-backlight = <20>; + qcom,disp-doze-hbm-backlight = <266>; + qcom,disp-fod-off-dimming-delay = <85>; + + qcom,elvss_dimming_check_enable; + qcom,mdss-dsi-panel-elvss-dimming-read-length = <1>; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command = [39 01 00 00 00 00 02 B0 07]; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command = [06 01 00 01 00 00 01 B7]; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <64>; + qcom,mdss-dsi-v-front-porch = <64>; + qcom,mdss-dsi-v-pulse-width = <20>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1100000000>; + qcom,mdss-dsi-panel-jitter = <0x5 0x1>; + qcom,mdss-dsi-on-command = [ + 05 01 00 00 0A 00 02 11 00 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 35 00 + 39 00 00 00 00 00 03 B7 01 4B + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 05 2B 00 00 09 23 + 39 00 00 00 00 00 03 F0 5A 5A /* esd */ + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 23 //osc + 39 00 00 00 00 00 02 D1 0F + 39 00 00 00 00 00 0C E9 11 55 A6 75 A3 B9 A1 4A 00 1A B8 + 39 00 00 00 00 00 07 E1 00 00 02 02 42 02 + 39 00 00 00 00 00 07 E2 00 00 00 00 00 00 + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 E1 19 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 39 00 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 51 00 00 + 39 01 00 00 43 00 02 55 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-doze-hbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 01 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-doze-lbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 00 00 02 53 23 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 10 00 02 28 00 + 39 01 00 00 00 00 02 53 20 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-doze-hbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-doze-lbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-acl-off-command = [39 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-dispparam-acl-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l1-command = [39 01 00 00 00 00 02 55 01];/* 50% */ + qcom,mdss-dsi-dispparam-acl-l1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l2-command = [39 01 00 00 00 00 02 55 02];/* 40% */ + qcom,mdss-dsi-dispparam-acl-l2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l3-command = [39 01 00 00 00 00 02 55 03];/* 30% */ + qcom,mdss-dsi-dispparam-acl-l3-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-hbm-off-command = [39 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-dispparam-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-on-command = [39 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-dispparam-hbm-on-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-dimmingon-command = [39 01 00 00 01 00 02 53 28]; + qcom,mdss-dsi-dispparam-dimmingon-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingoff-command = [39 01 00 00 01 00 02 53 20]; + qcom,mdss-dsi-dispparam-dimmingoff-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-srgb-on-command = [ + /* CRC Enable + sRGB mode */ + 39 01 00 00 00 00 02 81 90 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 BD 02 00 14 D1 00 04 07 AA 0C EC CB C8 0F DD D9 E4 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command = [ + /* CRC Enable + DCI-P3 mode */ + 39 01 00 00 00 00 02 81 91 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 D2 0A 05 1A E6 00 04 07 F5 0C DC DB E8 0F DD EE E9 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-off-command = [ + /* CRC Disable (Normal mode) */ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Bypass */ + 39 01 00 00 00 00 02 B1 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + + qcom,mdss-dsi-dispparam-hbm-fod-off-command = [ + 39 01 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 49 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 C9 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 11 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 02 53 E0 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 43 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-on-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/dsi-panel-ss-fhd-ea8076-global-cmd.dtsi b/arch/arm64/boot/dts/qcom/dsi-panel-ss-fhd-ea8076-global-cmd.dtsi new file mode 100644 index 000000000000..f238e97c07e4 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/dsi-panel-ss-fhd-ea8076-global-cmd.dtsi @@ -0,0 +1,244 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +/*--------------------------------------------------------------------------- + * This file is autogenerated file using gcdb parser. Please do not edit it. + * Update input XML file to add a new entry or update variable in this file + * VERSION = "1.0" + *---------------------------------------------------------------------------*/ +&soc { + dsi_ss_fhd_ea8076_global_cmd: qcom,mdss_dsi_ss_fhd_ea8076_global_cmd { + qcom,mdss-dsi-panel-name = "samsung ea8076 fhd cmd dsi panel"; + qcom,mdss-dsi-panel-id = <0>; + qcom,mdss-dsi-panel-model = "SAMSUNG FHD EA8076 CMD PANEL"; + qcom,mdss-dsi-panel-sleepwrmod = <0>; + qcom,mdss-dsi-panel-type = "dsi_cmd_mode"; + qcom,mdss-dsi-virtual-channel-id = <0>; + qcom,mdss-dsi-stream = <0>; + qcom,mdss-dsi-bpp = <24>; + qcom,mdss-dsi-underflow-color = <0xff>; + qcom,mdss-dsi-border-color = <0>; + qcom,mdss-dsi-traffic-mode = "burst_mode"; + qcom,mdss-dsi-bllp-eof-power-mode; + qcom,mdss-dsi-bllp-power-mode; + qcom,ulps-enabled; + qcom,mdss-dsi-lp11-init; + qcom,mdss-dsi-lane-0-state; + qcom,mdss-dsi-lane-1-state; + qcom,mdss-dsi-lane-2-state; + qcom,mdss-dsi-lane-3-state; + qcom,mdss-brightness-max-level = <2047>; + qcom,bl-update-flag = "delay_until_first_frame"; + qcom,mdss-dsi-dma-trigger = "trigger_sw"; + qcom,mdss-dsi-mdp-trigger = "none"; + qcom,mdss-dsi-bl-dcs-type-ss; + qcom,mdss-dsi-reset-sequence = <0 1>, <1 10>; + qcom,mdss-pan-physical-width-dimension = <68>; + qcom,mdss-pan-physical-height-dimension = <147>; + qcom,mdss-dsi-te-pin-select = <1>; + qcom,mdss-dsi-wr-mem-start = <0x2c>; + qcom,mdss-dsi-wr-mem-continue = <0x3c>; + qcom,mdss-dsi-te-dcs-command = <1>; + qcom,mdss-dsi-te-check-enable; + qcom,mdss-dsi-te-using-te-pin; + qcom,mdss-dsi-tx-eot-append; + qcom,mdss-dsi-panel-hdr-enabled; + qcom,mdss-dsi-panel-hdr-color-primaries = <14500 15500 32000 + 17000 15500 30000 8000 3000>; + qcom,mdss-dsi-panel-peak-brightness = <4300000>; + qcom,mdss-dsi-panel-blackness-level = <3230>; + + qcom,dispparam-enabled; + qcom,mdss-panel-on-dimming-delay = <120>; + /* IRQF_ONESHOT | IRQF_TRIGGER_FALLING */ + /* trig-flags: falling-0x0002 rasing-0x0001 */ + qcom,esd-err-irq-gpio = <&tlmm 5 0x2002>; + + qcom,disp-doze-lpm-backlight = <20>; + qcom,disp-doze-hbm-backlight = <266>; + qcom,disp-fod-off-dimming-delay = <85>; + + qcom,elvss_dimming_check_enable; + qcom,mdss-dsi-panel-elvss-dimming-read-length = <1>; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command = [39 01 00 00 00 00 02 B0 07]; + qcom,mdss-dsi-dispparam-elvss-dimming-offset-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command = [06 01 00 01 00 00 01 B7]; + qcom,mdss-dsi-dispparam-elvss-dimming-read-command-state = "dsi_hs_mode"; + + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-width = <1080>; + qcom,mdss-dsi-panel-height = <2340>; + qcom,mdss-dsi-h-front-porch = <64>; + qcom,mdss-dsi-h-back-porch = <64>; + qcom,mdss-dsi-h-pulse-width = <20>; + qcom,mdss-dsi-h-sync-skew = <0>; + qcom,mdss-dsi-v-back-porch = <64>; + qcom,mdss-dsi-v-front-porch = <64>; + qcom,mdss-dsi-v-pulse-width = <27>; + qcom,mdss-dsi-h-left-border = <0>; + qcom,mdss-dsi-h-right-border = <0>; + qcom,mdss-dsi-v-top-border = <0>; + qcom,mdss-dsi-v-bottom-border = <0>; + qcom,mdss-dsi-panel-framerate = <60>; + qcom,mdss-dsi-panel-clockrate = <1103000000>; + qcom,mdss-dsi-panel-jitter = <0x5 0x1>; + qcom,mdss-dsi-on-command = [ + 05 01 00 00 0A 00 02 11 00 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 35 00 + 39 00 00 00 00 00 03 B7 01 4B + 39 01 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 05 2B 00 00 09 23 + 39 00 00 00 00 00 03 F0 5A 5A /* esd */ + 39 00 00 00 00 00 03 FC 5A 5A + 39 00 00 00 00 00 02 B0 23 //osc + 39 00 00 00 00 00 02 D1 11 + 39 00 00 00 00 00 0C E9 11 55 A6 75 A3 B9 A1 4A 00 1A B8 + 39 00 00 00 00 00 07 E1 00 00 02 02 42 02 + 39 00 00 00 00 00 07 E2 00 00 00 00 00 00 + 39 00 00 00 00 00 02 B0 0C + 39 00 00 00 00 00 02 E1 19 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 00 00 03 FC A5 A5 + 39 00 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 51 00 00 + 39 01 00 00 43 00 02 55 00 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-off-command = [ + 05 01 00 00 00 00 02 28 00 + 05 01 00 00 78 00 02 10 00]; + qcom,mdss-dsi-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-off-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-doze-hbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 01 00 02 53 22 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-doze-lbm-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 D4 8B + 39 00 00 00 00 00 02 B0 A5 + 39 00 00 00 00 00 02 C7 00 + 39 00 00 00 00 00 02 B0 69 + 39 00 00 00 00 00 03 B9 08 8F + 39 01 00 00 00 00 02 53 23 + 39 01 00 00 00 00 03 F0 A5 A5]; + qcom,mdss-dsi-nolp-command = [ + 05 01 00 00 10 00 02 28 00 + 39 01 00 00 00 00 02 53 20 + 05 01 00 00 00 00 02 29 00]; + qcom,mdss-dsi-doze-hbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-doze-lbm-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-nolp-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-acl-off-command = [39 01 00 00 00 00 02 55 00]; + qcom,mdss-dsi-dispparam-acl-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l1-command = [39 01 00 00 00 00 02 55 01];/* 50% */ + qcom,mdss-dsi-dispparam-acl-l1-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l2-command = [39 01 00 00 00 00 02 55 02];/* 40% */ + qcom,mdss-dsi-dispparam-acl-l2-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-acl-l3-command = [39 01 00 00 00 00 02 55 03];/* 30% */ + qcom,mdss-dsi-dispparam-acl-l3-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-hbm-off-command = [39 01 00 00 00 00 02 53 28]; + qcom,mdss-dsi-dispparam-hbm-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-hbm-on-command = [39 01 00 00 00 00 02 53 E8]; + qcom,mdss-dsi-dispparam-hbm-on-command-state = "dsi_lp_mode"; + + qcom,mdss-dsi-dispparam-dimmingon-command = [39 01 00 00 01 00 02 53 28]; + qcom,mdss-dsi-dispparam-dimmingon-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-dimmingoff-command = [39 01 00 00 01 00 02 53 20]; + qcom,mdss-dsi-dispparam-dimmingoff-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-srgb-on-command = [ + /* CRC Enable + sRGB mode */ + 39 01 00 00 00 00 02 81 90 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 BD 02 00 14 D1 00 04 07 AA 0C EC CB C8 0F DD D9 E4 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-srgb-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command = [ + /* CRC Enable + DCI-P3 mode */ + 39 01 00 00 00 00 02 81 91 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Enable */ + 39 01 00 00 00 00 02 B1 00 + /* Set Offset P2*/ + 39 01 00 00 00 00 02 B0 01 + /* CRC LUT(sRGB mode) */ + 39 01 00 00 00 00 16 B1 AE 0C 05 3F C6 14 05 07 AA 4A DD C8 C3 14 C0 E8 DC 19 FF F4 D9 + /* Set Offset P23*/ + 39 01 00 00 00 00 02 B0 16 + /* CRC LUT(DCI-P3 mode) */ + 39 01 00 00 00 00 16 B1 D2 0A 05 1A E6 00 04 07 F5 0C DC DB E8 0F DD EE E9 05 FF FF FF + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-dcip3-on-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-crc-off-command = [ + /* CRC Disable (Normal mode) */ + 39 01 00 00 00 00 02 81 00 + 39 01 00 00 00 00 03 F0 5A 5A + /* CRC Bypass */ + 39 01 00 00 00 00 02 B1 01 + 39 01 00 00 00 00 03 F0 A5 A5 + ]; + qcom,mdss-dsi-dispparam-crc-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-elvss-dimming-off-command-state = "dsi_lp_mode"; + qcom,mdss-dsi-h-sync-pulse = <0>; + + qcom,mdss-dsi-dispparam-hbm-fod-off-command = [ + 39 01 00 00 00 00 02 53 20 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 4B + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 49 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 91 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-off-command-state = "dsi_hs_mode"; + qcom,mdss-dsi-dispparam-hbm-fod-on-command = [ + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 02 B0 03 + 39 00 00 00 00 00 02 B7 C9 + 39 00 00 00 00 00 02 B0 07 + 39 00 00 00 00 00 02 B7 11 + 39 00 00 00 00 00 03 F0 A5 A5 + 39 01 00 00 01 00 02 53 E0 + 39 00 00 00 00 00 03 F0 5A 5A + 39 00 00 00 00 00 03 B7 01 43 + 39 01 00 00 01 00 03 F0 A5 A5]; + qcom,mdss-dsi-dispparam-hbm-fod-on-command-state = "dsi_hs_mode"; + }; + }; + }; +}; diff --git a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi index 64977c7c9653..cf398ae46599 100644 --- a/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi +++ b/arch/arm64/boot/dts/qcom/fg-gen4-batterydata-alium-3600mah.dtsi @@ -11,33 +11,39 @@ * GNU General Public License for more details. */ + qcom,alium_860_89032_0000_3600mah_averaged_masterslave_sep24th2018 { /* #Alium_860_89032_0000_3600mAh_averaged_MasterSlave_Sept24th2018*/ - qcom,max-voltage-uv = <4350000>; - qcom,fastchg-current-ma = <5400>; - qcom,jeita-fcc-ranges = <0 100 2500000 - 101 400 3600000 - 401 450 2500000>; - qcom,jeita-fv-ranges = <0 100 4250000 - 101 400 4350000 - 401 450 4250000>; - qcom,step-chg-ranges = <3600000 3800000 5400000 - 3800001 4300000 3600000 - 4300001 4350000 2500000>; + qcom,max-voltage-uv = <4400000>; + qcom,fastchg-current-ma = <4800>; + qcom,jeita-fcc-ranges = <0 50 300000 + 51 100 1600000 + 101 150 3200000 + 151 450 4800000 + 451 580 1600000>; + qcom,jeita-fv-ranges = <0 50 4400000 + 51 100 4400000 + 101 150 4400000 + 151 450 4400000 + 451 580 4100000>; + qcom,step-chg-ranges = <3600000 4200000 3000000 + 4201000 4300000 3000000 + 4301000 4340000 2500000>; + qcom,nom-batt-capacity-mah = <3300>; + qcom,batt-id-kohm = <300>; /* COLD = 0 DegC, HOT = 45 DegC */ - qcom,jeita-hard-thresholds = <0x58cd 0x20b8>; + /* qcom,jeita-hard-thresholds = <0x58cd 0x20b8>; */ /* COOL = 10 DegC, WARM = 40 DegC */ - qcom,jeita-soft-thresholds = <0x4ccc 0x25e3>; + /* qcom,jeita-soft-thresholds = <0x4ccc 0x25e3>; */ /* COLD hys = 13 DegC, WARM hys = 37 DegC */ - qcom,jeita-soft-hys-thresholds = <0x48d4 0x2943>; + /*qcom,jeita-soft-hys-thresholds = <0x48d4 0x2943>; qcom,jeita-soft-fcc-ua = <2500000 2500000>; - qcom,jeita-soft-fv-uv = <4250000 4250000>; + qcom,jeita-soft-fv-uv = <4250000 4250000>;*/ qcom,ocv-based-step-chg; - qcom,batt-id-kohm = <107>; qcom,battery-beta = <4250>; qcom,therm-room-temp = <100000>; - qcom,fg-cc-cv-threshold-mv = <4340>; - qcom,battery-type = "alium_860_89032_0000_3600mah_sept24th2018"; + qcom,fg-cc-cv-threshold-mv = <4390>; + qcom,battery-type = "itech_3000mah"; qcom,therm-coefficients = <0x2318 0xd0c 0xdaf7 0xc556 0x848d>; qcom,therm-center-offset = <0x70>; qcom,therm-pull-up = <100>; diff --git a/arch/arm64/boot/dts/qcom/pm8150.dtsi b/arch/arm64/boot/dts/qcom/pm8150.dtsi index 4f780f07ecb8..d6b8eb94dd94 100644 --- a/arch/arm64/boot/dts/qcom/pm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150.dtsi @@ -42,17 +42,24 @@ compatible = "qcom,qpnp-power-on"; reg = <0x800 0x100>; interrupts = <0x0 0x8 0x0 IRQ_TYPE_NONE>, - <0x0 0x8 0x1 IRQ_TYPE_NONE>; - interrupt-names = "kpdpwr", "resin"; - qcom,pon-dbc-delay = <15625>; + <0x0 0x8 0x1 IRQ_TYPE_NONE>, + <0x0 0x8 0x4 IRQ_TYPE_NONE>, + <0x0 0x8 0x5 IRQ_TYPE_NONE>; + interrupt-names = "kpdpwr", "resin", + "resin-bark", "kpdpwr-resin-bark"; + qcom,pon-dbc-delay = <62500>; qcom,kpdpwr-sw-debounce; qcom,system-reset; qcom,store-hard-reset-reason; qcom,pon_1 { qcom,pon-type = ; - qcom,pull-up; + qcom,support-reset = <1>; + qcom,pull-up = <1>; linux,code = ; + qcom,s1-timer = <4480>; + qcom,s2-timer = <2000>; + qcom,s2-type = <0x7>; }; qcom,pon_2 { @@ -60,6 +67,16 @@ qcom,pull-up; linux,code = ; }; + + qcom,pon_3 { + qcom,pon-type = ; + qcom,support-reset = <1>; + qcom,pull-up = <1>; + qcom,s1-timer = <1352>; + qcom,s2-timer = <2000>; + qcom,s2-type = <0x1>; + qcom,use-bark; + }; }; pm8150_clkdiv: clock-controller@5b00 { @@ -78,7 +95,7 @@ #address-cells = <1>; #size-cells = <1>; qcom,qpnp-rtc-write = <0>; - qcom,qpnp-rtc-alarm-pwrup = <0>; + qcom,qpnp-rtc-alarm-pwrup = <1>; qcom,pm8150_rtc_rw@6000 { reg = <0x6000 0x100>; diff --git a/arch/arm64/boot/dts/qcom/pm8150b.dtsi b/arch/arm64/boot/dts/qcom/pm8150b.dtsi index e1ff572b262d..e892b2a48b5f 100644 --- a/arch/arm64/boot/dts/qcom/pm8150b.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150b.dtsi @@ -74,6 +74,7 @@ <0x2 0xc1 0 IRQ_TYPE_NONE>, <0x2 0xc4 0 IRQ_TYPE_NONE>, <0x2 0xc5 0 IRQ_TYPE_NONE>, + <0x2 0xc6 0 IRQ_TYPE_NONE>, <0x2 0xc7 0 IRQ_TYPE_NONE>, <0x2 0xc8 0 IRQ_TYPE_NONE>, <0x2 0xc9 0 IRQ_TYPE_NONE>, @@ -81,12 +82,12 @@ <0x2 0xcb 0 IRQ_TYPE_NONE>; interrupt-names = "pm8150b_gpio1", "pm8150b_gpio2", "pm8150b_gpio5", "pm8150b_gpio6", - "pm8150b_gpio8", "pm8150b_gpio9", - "pm8150b_gpio10", "pm8150b_gpio11", - "pm8150b_gpio12"; + "pm8150b_gpio7", "pm8150b_gpio8", + "pm8150b_gpio9", "pm8150b_gpio10", + "pm8150b_gpio11", "pm8150b_gpio12"; gpio-controller; #gpio-cells = <2>; - qcom,gpios-disallowed = <3 4 7>; + qcom,gpios-disallowed = <3 4>; }; pm8150b_vadc: vadc@3100 { @@ -737,6 +738,7 @@ wake-capable-sensor; tracks-low; + disable-thermal-zone; trips { soc_trip:soc-trip { temperature = <10>; diff --git a/arch/arm64/boot/dts/qcom/pm8150l.dtsi b/arch/arm64/boot/dts/qcom/pm8150l.dtsi index 3586af695f4f..9a1c0eeb1332 100644 --- a/arch/arm64/boot/dts/qcom/pm8150l.dtsi +++ b/arch/arm64/boot/dts/qcom/pm8150l.dtsi @@ -233,7 +233,7 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - status = "disabled"; + //status = "disabled"; }; pm8150l_torch0: qcom,torch_0 { @@ -270,7 +270,7 @@ qcom,ires-ua = <12500>; qcom,hdrm-voltage-mv = <325>; qcom,hdrm-vol-hi-lo-win-mv = <100>; - status = "disabled"; + //status = "disabled"; }; pm8150l_switch0: qcom,led_switch_0 { @@ -293,6 +293,19 @@ qcom,led-mask = <3>; qcom,default-led-trigger = "switch2_trigger"; }; + + pm8150l_flashlight: qcom,flashlight { + label = "flash"; + qcom,led-name = "flashlight"; + qcom,max-current = <750>; + qcom,default-led-trigger = "flashlight_trigger"; + qcom,id = <3>; + qcom,current-ma = <500>; + qcom,duration-ms = <1280>; + qcom,ires-ua = <12500>; + qcom,hdrm-voltage-mv = <325>; + qcom,hdrm-vol-hi-lo-win-mv = <100>; + }; }; pm8150l_wled: qcom,wled@d800 { @@ -334,7 +347,7 @@ qcom,num-lpg-channels = <3>; qcom,lut-patterns = <0 10 20 30 40 50 60 70 80 90 100 90 80 70 60 50 40 30 20 10 0>; - lpg1 { + pwm_lpg1: lpg1 { qcom,lpg-chan-id = <1>; qcom,ramp-step-ms = <100>; qcom,ramp-pause-hi-count = <2>; @@ -345,7 +358,7 @@ qcom,ramp-pattern-repeat; }; - lpg2 { + pwm_lpg2: lpg2 { qcom,lpg-chan-id = <2>; qcom,ramp-step-ms = <100>; qcom,ramp-pause-hi-count = <2>; @@ -356,7 +369,7 @@ qcom,ramp-pattern-repeat; }; - lpg3 { + pwm_lpg3: lpg3 { qcom,lpg-chan-id = <3>; qcom,ramp-step-ms = <100>; qcom,ramp-pause-hi-count = <2>; @@ -374,24 +387,24 @@ reg-names = "lpg-base"; #pwm-cells = <2>; qcom,num-lpg-channels = <2>; + status = "disabled"; }; pm8150l_rgb_led: qcom,leds@d000 { compatible = "qcom,tri-led"; reg = <0xd000 0x100>; - red { + red_led: red { label = "red"; pwms = <&pm8150l_lpg 0 1000000>; led-sources = <0>; - linux,default-trigger = "timer"; }; - green { + green_led: green { label = "green"; pwms = <&pm8150l_lpg 1 1000000>; led-sources = <1>; linux,default-trigger = "timer"; }; - blue { + blue_led: blue { label = "blue"; pwms = <&pm8150l_lpg 2 1000000>; led-sources = <2>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi index 980a8bf9763e..6af6feb50540 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-audio-overlay.dtsi @@ -16,6 +16,7 @@ #include &snd_9360 { + status = "disabled"; qcom,ext-disp-audio-rx = <1>; qcom,wcn-btfm = <1>; qcom,mi2s-audio-intf = <1>; @@ -72,9 +73,10 @@ "MADINPUT", "MCLK", "hifi amp", "LINEOUT1", "hifi amp", "LINEOUT2", + "AMIC1", "MIC BIAS1", "AMIC2", "MIC BIAS2", "MIC BIAS2", "Headset Mic", - "AMIC3", "MIC BIAS2", + "AMIC3", "MIC BIAS3", "MIC BIAS2", "ANCRight Headset Mic", "AMIC4", "MIC BIAS2", "MIC BIAS2", "ANCLeft Headset Mic", @@ -95,8 +97,8 @@ "SpkrLeft IN", "SPK1 OUT", "SpkrRight IN", "SPK2 OUT"; - qcom,msm-mbhc-hphl-swh = <1>; - qcom,msm-mbhc-gnd-swh = <1>; + qcom,msm-mbhc-hphl-swh = <0>; + qcom,msm-mbhc-gnd-swh = <0>; qcom,msm-mbhc-hs-mic-max-threshold-mv = <1700>; qcom,msm-mbhc-hs-mic-min-threshold-mv = <50>; qcom,hph-en0-gpio = <&tavil_hph_en0>; @@ -107,11 +109,21 @@ asoc-codec-names = "msm-stub-codec.1", "msm-ext-disp-audio-codec-rx"; - qcom,wsa-max-devs = <2>; + qcom,wsa-max-devs = <0>; qcom,wsa-devs = <&wsa881x_70211>, <&wsa881x_70212>, <&wsa881x_70213>, <&wsa881x_70214>; qcom,wsa-aux-dev-prefix = "SpkrLeft", "SpkrRight", "SpkrLeft", "SpkrRight"; + + /* pinctrl-names = "quat-mi2s-active", "quat-mi2s-sleep"; */ + pinctrl-names = "quat_mi2s_enable", "quat_mi2s_disable", + "quat_tdm_enable", "quat_tdm_disable"; + pinctrl-0 = <&quat_mi2s_active &quat_mi2s_sd0_active + &quat_mi2s_sd1_active>; + pinctrl-1 = <&quat_mi2s_sleep &quat_mi2s_sd0_sleep + &quat_mi2s_sd1_sleep>; + pinctrl-2 = <&quat_tdm_active &quat_tdm_dout_active>; + pinctrl-3 = <&quat_tdm_sleep &quat_tdm_dout_sleep>; }; &soc { @@ -290,10 +302,10 @@ "cdc-vddpx-1", "cdc-vdd-3v3"; - qcom,cdc-micbias1-mv = <1800>; + qcom,cdc-micbias1-mv = <2700>; qcom,cdc-micbias2-mv = <1800>; - qcom,cdc-micbias3-mv = <1800>; - qcom,cdc-micbias4-mv = <1800>; + qcom,cdc-micbias3-mv = <2700>; + qcom,cdc-micbias4-mv = <2700>; qcom,cdc-mclk-clk-rate = <9600000>; qcom,cdc-slim-ifd = "tavil-slim-ifd"; diff --git a/arch/arm64/boot/dts/qcom/sm8150-audio.dtsi b/arch/arm64/boot/dts/qcom/sm8150-audio.dtsi index 32e1ec1a75b7..29875f1cd2d8 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-audio.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-audio.dtsi @@ -94,6 +94,7 @@ compatible = "qcom,sm8150-asoc-snd-tavil"; qcom,model = "sm8150-tavil-snd-card"; + qcom,msm-mbhc-usbc-audio-supported = <1>; asoc-platform = <&pcm0>, <&pcm1>, <&pcm2>, <&voip>, <&voice>, <&loopback>, <&compress>, <&hostless>, <&afe>, <&lsm>, <&routing>, <&compr>, @@ -151,15 +152,15 @@ "msm-dai-q6-tdm.36912", "msm-dai-q6-tdm.36913", "msm-dai-q6-tdm.36914", "msm-dai-q6-tdm.36928", "msm-dai-q6-tdm.36929"; - fsa4480-i2c-handle = <&fsa4480>; + //fsa4480-i2c-handle = <&fsa4480>; }; }; &qupv3_se4_i2c { status = "ok"; - fsa4480: fsa4480@43 { + fsa4480: fsa4480@42 { compatible = "qcom,fsa4480-i2c"; - reg = <0x43>; + reg = <0x42>; pinctrl-names = "default"; pinctrl-0 = <&fsa_usbc_ana_en>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi index c20f5a7b7eeb..da58c9300a7e 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-camera.dtsi @@ -168,7 +168,7 @@ hw-thd-dat = <22>; hw-thd-sta = <162>; hw-tbuf = <227>; - hw-scl-stretch-en = <0>; + hw-scl-stretch-en = <1>; hw-trdhld = <6>; hw-tsp = <3>; cci-clk-src = <37500000>; @@ -183,7 +183,7 @@ hw-thd-dat = <22>; hw-thd-sta = <35>; hw-tbuf = <62>; - hw-scl-stretch-en = <0>; + hw-scl-stretch-en = <1>; hw-trdhld = <6>; hw-tsp = <3>; cci-clk-src = <37500000>; @@ -198,7 +198,7 @@ hw-thd-dat = <22>; hw-thd-sta = <35>; hw-tbuf = <62>; - hw-scl-stretch-en = <1>; + hw-scl-stretch-en = <0>; hw-trdhld = <6>; hw-tsp = <3>; cci-clk-src = <37500000>; @@ -263,7 +263,7 @@ hw-thd-dat = <22>; hw-thd-sta = <162>; hw-tbuf = <227>; - hw-scl-stretch-en = <0>; + hw-scl-stretch-en = <1>; hw-trdhld = <6>; hw-tsp = <3>; cci-clk-src = <37500000>; @@ -278,7 +278,7 @@ hw-thd-dat = <22>; hw-thd-sta = <35>; hw-tbuf = <62>; - hw-scl-stretch-en = <0>; + hw-scl-stretch-en = <1>; hw-trdhld = <6>; hw-tsp = <3>; cci-clk-src = <37500000>; @@ -293,7 +293,7 @@ hw-thd-dat = <22>; hw-thd-sta = <35>; hw-tbuf = <62>; - hw-scl-stretch-en = <1>; + hw-scl-stretch-en = <0>; hw-trdhld = <6>; hw-tsp = <3>; cci-clk-src = <37500000>; diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu-v2.dtsi index bbf88b802122..59dc1fde6904 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu-v2.dtsi @@ -14,6 +14,11 @@ gpu_opp_table_v2: gpu_opp_table_v2 { compatible = "operating-points-v2"; + opp-810000000 { + opp-hz = /bits/ 64 <810000000>; + opp-microvolt = ; + }; + opp-675000000 { opp-hz = /bits/ 64 <675000000>; opp-microvolt = ; diff --git a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi index 3dbcdb82af51..080048f93249 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-gpu.dtsi @@ -82,7 +82,7 @@ qcom,gpu-quirk-secvid-set-once; qcom,gpu-quirk-cx-gdsc; - qcom,idle-timeout = <80>; //msecs + qcom,idle-timeout = <64>; //msecs qcom,no-nap; qcom,highest-bank-bit = <15>; @@ -100,8 +100,6 @@ tzone-names = "gpuss-0-usr", "gpuss-1-usr"; - qcom,pm-qos-active-latency = <44>; - clocks = <&clock_gpucc GPU_CC_CXO_CLK>, <&clock_gcc GCC_DDRSS_GPU_AXI_CLK>, <&clock_gcc GCC_GPU_MEMNOC_GFX_CLK>, diff --git a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi index cb479b44193d..34c411846ec0 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pinctrl.dtsi @@ -344,6 +344,7 @@ pins = "gpio122"; drive-strength = <2>; bias-pull-down; + input-enable; }; }; }; @@ -357,7 +358,8 @@ config { pins = "gpio54"; drive-strength = <2>; - bias-pull-down; + bias-disable; + output-low; }; }; }; @@ -1148,12 +1150,12 @@ /* active state */ mux { /* 41: NFC ENABLE 42:ESE Enable */ - pins = "gpio41", "gpio42", "gpio48"; + pins = "gpio41", "gpio48"; function = "gpio"; }; config { - pins = "gpio41", "gpio42", "gpio48"; + pins = "gpio41", "gpio48"; drive-strength = <2>; /* 2 MA */ bias-pull-up; }; @@ -1163,12 +1165,12 @@ /* sleep state */ mux { /* 41: NFC ENABLE 42:ESE Enable */ - pins = "gpio41", "gpio42", "gpio48"; + pins = "gpio41", "gpio48"; function = "gpio"; }; config { - pins = "gpio41", "gpio42", "gpio48"; + pins = "gpio41", "gpio48"; drive-strength = <2>; /* 2 MA */ bias-disable; }; @@ -2465,6 +2467,19 @@ }; tert_tdm { + cs35l41_int_default: cs35l41_int_default { + mux { + pins = "gpio10"; + function = "gpio"; + }; + config { + pins = "gpio10"; + bias-pull-up; + drive-strength = <8>; + input-enable; + }; + }; + tert_tdm_sleep: tert_tdm_sleep { mux { pins = "gpio133", "gpio134"; @@ -3722,6 +3737,63 @@ }; }; + /* USB C analog configuration */ + wcd_usbc_analog_en1 { + wcd_usbc_analog_en1_idle: wcd_usbc_ana_en1_idle { + mux { + pins = "gpio35"; + function = "gpio"; + }; + config { + pins = "gpio35"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en1_active: wcd_usbc_ana_en1_active { + mux { + pins = "gpio35"; + function = "gpio"; + }; + config { + pins = "gpio35"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + + wcd_usbc_analog_en2 { + wcd_usbc_analog_en2_idle: wcd_usbc_ana_en2_idle { + mux { + pins = "gpio58"; + function = "gpio"; + }; + config { + pins = "gpio58"; + drive-strength = <2>; + bias-pull-down; + output-low; + }; + }; + + wcd_usbc_analog_en2_active: wcd_usbc_ana_en2_active { + mux { + pins = "gpio58"; + function = "gpio"; + }; + config { + pins = "gpio58"; + drive-strength = <2>; + bias-disable; + output-high; + }; + }; + }; + fsa_usbc_ana_en_n@100 { fsa_usbc_ana_en: fsa_usbc_ana_en { mux { diff --git a/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi b/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi index f1c4666aa1a3..18ccdc3bd4f8 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-pmic-overlay.dtsi @@ -130,6 +130,27 @@ power-source = <0>; }; }; + + otg_vbus_boost { + otg_vbus_boost_default: otg_vbus_boost_default { + pins = "gpio12"; + function = "normal"; + output-low; + power-source = <0>; + }; + }; + + power_good { + /*Get the DC Power Good signal*/ + power_good_default: power_good_default { + pins = "gpio7"; + function = "normal"; + qcom,drive-strength = <2>; /* 2 MA */ + bias-disable; /* NO pull */ + power-source = <1>; + input-enable; + }; + }; }; &usb0 { diff --git a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi index 10b07a2dd36d..b8650a813b97 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-qrd.dtsi @@ -95,6 +95,19 @@ pinctrl-0 = <&key_home_default>; qcom,finger-detect-gpio = <&pm8150_gpios 1 0>; }; + + display_panel_avdd_eldo: display-gpio-regulator@0 { + compatible = "regulator-fixed"; + regulator-name = "display_panel_avdd_eldo"; + regulator-min-microvolt = <1800000>; + regulator-max-microvolt = <1800000>; + regulator-enable-ramp-delay = <233>; + gpio = <&tlmm 130 0>; + enable-active-high; + regulator-boot-on; + pinctrl-names = "default"; + pintctrl-0 = <&display_panel_avdd_eldo_default>; + }; }; &qupv3_se17_i2c { @@ -114,7 +127,7 @@ pinctrl-0 = <&ts_active>; pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>; st,irq-gpio = <&tlmm 122 0x2008>; - st,reset-gpio = <&tlmm 54 0x00>; + //st,reset-gpio = <&tlmm 54 0x00>; st,regulator_dvdd = "vdd"; st,regulator_avdd = "avdd"; }; @@ -220,6 +233,21 @@ qcom,dsi-display-active; }; +&tlmm { + display_panel_avdd_eldo_default: display_panel_avdd_eldo_default { + mux { + pins = "gpio130"; + function = "gpio"; + }; + config { + pins = "gpio130"; + drive-strength = <8>; + bias-disable = <0>; + output-high; + }; + }; +}; + &sde_dsi { vdd-supply = <&display_panel_avdd_eldo>; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi b/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi index 2d819211594a..ebbf84cc7ad3 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-regulator.dtsi @@ -389,9 +389,9 @@ L13A: pm8150_l13: regulator-pm8150-l13 { regulator-name = "pm8150_l13"; qcom,set = ; - regulator-min-microvolt = <2704000>; - regulator-max-microvolt = <2704000>; - qcom,init-voltage = <2704000>; + regulator-min-microvolt = <3000000>; + regulator-max-microvolt = <3000000>; + qcom,init-voltage = <3000000>; qcom,init-mode = ; }; }; diff --git a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi index a3636a067f11..3837a06d26c2 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-sde-display.dtsi @@ -31,9 +31,17 @@ #include "dsi-panel-sw43404-amoled-dsc-wqhd-cmd.dtsi" #include "dsi-panel-sw43404-amoled-dsc-wqhd-video.dtsi" #include "dsi-panel-sw43404-amoled-dsc-fhd-plus-cmd.dtsi" +#include "dsi-panel-samsung-fhd-ea8076-cmd.dtsi" +#include "dsi-panel-samsung-fhd-ea8076-f1-cmd.dtsi" +#include "dsi-panel-samsung-fhd-ea8076-f1p2-cmd.dtsi" +#include "dsi-panel-samsung-fhd-ea8076-f1p2-2-cmd.dtsi" +#include "dsi-panel-samsung-fhd-ea8076-f1mp-cmd.dtsi" #include "dsi-panel-nt36850-truly-dualmipi-wqhd-cmd.dtsi" +#include "dsi-panel-ss-fhd-ea8076-cmd.dtsi" +#include "dsi-panel-ss-fhd-ea8076-global-cmd.dtsi" #include +/* &tlmm { display_panel_avdd_eldo_default: display_panel_avdd_eldo_default { mux { @@ -48,6 +56,7 @@ }; }; }; +*/ &soc { dsi_panel_pwr_supply: dsi_panel_pwr_supply { @@ -168,6 +177,7 @@ }; }; + /* display_panel_avdd_eldo: display-gpio-regulator@0 { compatible = "regulator-fixed"; regulator-name = "display_panel_avdd_eldo"; @@ -180,6 +190,33 @@ pinctrl-names = "default"; pintctrl-0 = <&display_panel_avdd_eldo_default>; }; + */ + + dsi_amoled_panel_pwr_supply: dsi_amoled_panel_pwr_supply { + #address-cells = <1>; + #size-cells = <0>; + + qcom,panel-supply-entry@0 { + reg = <0>; + qcom,supply-name = "vddio"; + qcom,supply-min-voltage = <1800000>; + qcom,supply-max-voltage = <1800000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + //qcom,supply-post-on-sleep = <20>; + }; + + qcom,panel-supply-entry@1 { + reg = <1>; + qcom,supply-name = "vci"; + qcom,supply-min-voltage = <3000000>; + qcom,supply-max-voltage = <3000000>; + qcom,supply-enable-load = <62000>; + qcom,supply-disable-load = <80>; + qcom,supply-post-on-sleep = <10>; + qcom,supply-pre-off-sleep = <10>; + }; + }; dsi_sharp_4k_dsc_video_display: qcom,dsi-display@0 { label = "dsi_sharp_4k_dsc_video_display"; @@ -437,6 +474,85 @@ qcom,dsi-panel = <&dsi_sim_sec_hd_cmd>; }; + dsi_samsung_fhd_ea8076_cmd_display: qcom,dsi-display@23 { + label = "dsi_samsung_fhd_ea8076_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,dsi-panel = <&dsi_samsung_fhd_ea8076_cmd>; + }; + + dsi_samsung_fhd_ea8076_f1_cmd_display: qcom,dsi-display@24 { + label = "dsi_samsung_fhd_ea8076_f1_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,dsi-panel = <&dsi_samsung_fhd_ea8076_f1_cmd>; + }; + + dsi_samsung_fhd_ea8076_f1mp_cmd_display: qcom,dsi-display@25 { + label = "dsi_samsung_fhd_ea8076_f1mp_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,dsi-panel = <&dsi_samsung_fhd_ea8076_f1mp_cmd>; + }; + + dsi_samsung_fhd_ea8076_f1p2_2_cmd_display: qcom,dsi-display@26 { + label = "dsi_samsung_fhd_ea8076_f1p2_2_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,dsi-panel = <&dsi_samsung_fhd_ea8076_f1p2_2_cmd>; + }; + + dsi_samsung_fhd_ea8076_f1p2_cmd_display: qcom,dsi-display@27 { + label = "dsi_samsung_fhd_ea8076_f1p2_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,dsi-panel = <&dsi_samsung_fhd_ea8076_f1p2_cmd>; + }; + + dsi_ss_fhd_ea8076_cmd_display: qcom,dsi-display@28 { + + label = "dsi_ss_fhd_ea8076_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,dsi-panel = <&dsi_ss_fhd_ea8076_cmd>; + }; + + dsi_ss_fhd_ea8076_global_cmd_display: qcom,dsi-display@29 { + + label = "dsi_ss_fhd_ea8076_global_cmd_display"; + qcom,display-type = "primary"; + + qcom,dsi-ctrl-num = <0>; + qcom,dsi-phy-num = <0>; + qcom,dsi-select-clocks = "mux_byte_clk0", "mux_pixel_clk0"; + + qcom,dsi-panel = <&dsi_ss_fhd_ea8076_global_cmd>; + }; + sde_dsi: qcom,dsi-display-primary { compatible = "qcom,dsi-display"; label = "primary"; @@ -467,7 +583,8 @@ vddio-supply = <&pm8150_l14>; lab-supply = <&lcdb_ldo_vreg>; ibb-supply = <&lcdb_ncp_vreg>; - vdd-supply = <&display_panel_avdd_eldo>; + //vdd-supply = <&display_panel_avdd_eldo>; + vci-supply = <&pm8150_l13>; qcom,dsi-display-list = <&dsi_sharp_4k_dsc_video_display @@ -489,7 +606,14 @@ &dsi_nt35695b_truly_fhd_video_display &dsi_sw43404_amoled_video_display &dsi_sw43404_amoled_fhd_plus_cmd_display - &dsi_dual_nt36850_truly_cmd_display>; + &dsi_dual_nt36850_truly_cmd_display + &dsi_samsung_fhd_ea8076_cmd_display + &dsi_samsung_fhd_ea8076_f1_cmd_display + &dsi_samsung_fhd_ea8076_f1mp_cmd_display + &dsi_samsung_fhd_ea8076_f1p2_2_cmd_display + &dsi_samsung_fhd_ea8076_f1p2_cmd_display + &dsi_ss_fhd_ea8076_cmd_display + &dsi_ss_fhd_ea8076_global_cmd_display>; }; sde_dsi1: qcom,dsi-display-secondary { @@ -522,7 +646,7 @@ vddio-supply = <&pm8150_l14>; lab-supply = <&lcdb_ldo_vreg>; ibb-supply = <&lcdb_ncp_vreg>; - vdd-supply = <&display_panel_avdd_eldo>; + //vdd-supply = <&display_panel_avdd_eldo>; qcom,dsi-display-list = <&dsi_nt35695b_truly_fhd_cmd_sec_display @@ -548,7 +672,7 @@ &sde_dp { qcom,dp-usbpd-detection = <&pm8150b_pdphy>; qcom,ext-disp = <&ext_disp>; - qcom,dp-aux-switch = <&fsa4480>; + //qcom,dp-aux-switch = <&fsa4480>; qcom,usbplug-cc-gpio = <&tlmm 38 0>; @@ -955,3 +1079,94 @@ }; }; +&dsi_samsung_fhd_ea8076_cmd { + qcom,mdss-dsi-t-clk-post = <0x1A>; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 + 0A 06 03 04 00 1E 1A]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_fhd_ea8076_f1_cmd { + qcom,mdss-dsi-t-clk-post = <0x1A>; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 + 0A 06 03 04 00 1E 1A]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_fhd_ea8076_f1mp_cmd { + qcom,mdss-dsi-t-clk-post = <0x1A>; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 + 0A 06 03 04 00 1E 1A]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_fhd_ea8076_f1p2_cmd { + qcom,mdss-dsi-t-clk-post = <0x1A>; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 + 0A 06 03 04 00 1E 1A]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_samsung_fhd_ea8076_f1p2_2_cmd { + qcom,mdss-dsi-t-clk-post = <0x1A>; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 + 0A 06 03 04 00 1E 1A]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_ss_fhd_ea8076_cmd { + qcom,mdss-dsi-t-clk-post = <0x0F>; + qcom,mdss-dsi-t-clk-pre = <0x37>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 25 09 + 0A 06 03 04 00 1E 1A]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + +&dsi_ss_fhd_ea8076_global_cmd { + qcom,mdss-dsi-t-clk-post = <0x1A>; + qcom,mdss-dsi-t-clk-pre = <0x1E>; + qcom,mdss-dsi-display-timings { + timing@0{ + qcom,mdss-dsi-panel-phy-timings = [00 24 0A 0A 26 24 0A + 0A 06 03 04 00 1E 1A]; + qcom,display-topology = <1 0 1>; + qcom,default-topology-index = <0>; + }; + }; +}; + diff --git a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi index 737195c6a3ea..663958958ca9 100644 --- a/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150-v2.dtsi @@ -93,6 +93,11 @@ #include "msm-arm-smmu-sm8150-v2.dtsi" &pcie0 { + + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 500 2000000>; + reg = <0x1c00000 0x4000>, <0x1c06000 0x1000>, <0x60000000 0xf1d>, @@ -203,6 +208,11 @@ }; &pcie1 { + + qcom,msm-bus,vectors-KBps = + <100 512 0 0>, + <100 512 500 2000000>; + reg = <0x1c08000 0x4000>, <0x1c0e000 0x2000>, <0x40000000 0xf1d>, diff --git a/arch/arm64/boot/dts/qcom/sm8150.dtsi b/arch/arm64/boot/dts/qcom/sm8150.dtsi index 2799385f733a..9100b39db54b 100644 --- a/arch/arm64/boot/dts/qcom/sm8150.dtsi +++ b/arch/arm64/boot/dts/qcom/sm8150.dtsi @@ -61,6 +61,7 @@ serial0 = &qupv3_se12_2uart; hsuart0 = &qupv3_se13_4uart; spi0 = &qupv3_se3_spi; + spi1 = &qupv3_se1_spi; i2c0 = &qupv3_se4_i2c; }; @@ -574,7 +575,7 @@ compatible = "android,firmware"; shared_meta: vbmeta { compatible = "android,vbmeta"; - parts = "vbmeta,boot,system,vendor,dtbo,odm"; + parts = "vbmeta,boot,system,vendor,dtbo"; }; android_q_fstab: fstab { compatible = "android,fstab"; @@ -583,15 +584,7 @@ dev = "/dev/block/platform/soc/8804000.sdhci/by-name/vendor"; type = "ext4"; mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait,slotselect,avb"; - status = "ok"; - }; - odm { - compatible = "android,odm"; - dev = "/dev/block/platform/soc/8804000.sdhci/by-name/odm"; - type = "ext4"; - mnt_flags = "ro,barrier=1,discard"; - fsmgr_flags = "wait,slotselect,avb"; + fsmgr_flags = "wait,avb"; status = "ok"; }; }; @@ -644,55 +637,55 @@ pil_adsp_mem: pil_adsp_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x8be00000 0x0 0x1a00000>; + reg = <0x0 0x8be00000 0x0 0x2200000>; }; pil_modem_mem: modem_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x8d800000 0x0 0x9600000>; + reg = <0x0 0x8e000000 0x0 0x9600000>; }; pil_video_mem: pil_video_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x96e00000 0x0 0x500000>; + reg = <0x0 0x97600000 0x0 0x500000>; }; pil_slpi_mem: pil_slpi_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x97300000 0x0 0x1400000>; + reg = <0x0 0x97b00000 0x0 0x1400000>; }; pil_ipa_fw_mem: pil_ipa_fw_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x98700000 0x0 0x10000>; + reg = <0x0 0x98f00000 0x0 0x10000>; }; pil_ipa_gsi_mem: pil_ipa_gsi_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x98710000 0x0 0x5000>; + reg = <0x0 0x98f10000 0x0 0x5000>; }; pil_gpu_mem: pil_gpu_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x98715000 0x0 0x2000>; + reg = <0x0 0x98f15000 0x0 0x2000>; }; pil_spss_mem: pil_spss_region { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x98800000 0x0 0x100000>; + reg = <0x0 0x99000000 0x0 0x100000>; }; pil_cdsp_mem: cdsp_regions { compatible = "removed-dma-pool"; no-map; - reg = <0x0 0x98900000 0x0 0x1400000>; + reg = <0x0 0x99100000 0x0 0x1400000>; }; qseecom_mem: qseecom_region { @@ -712,11 +705,6 @@ label = "cont_splash_region"; }; - disp_rdump_memory: disp_rdump_region { - reg = <0x0 0x9c000000 0x0 0x02400000>; - label = "disp_rdump_region"; - }; - adsp_mem: adsp_region { compatible = "shared-dma-pool"; alloc-ranges = <0x0 0x00000000 0x0 0xffffffff>; @@ -3003,7 +2991,7 @@ qcom_seecom: qseecom@87900000 { compatible = "qcom,qseecom"; - reg = <0x87900000 0x2200000>; + reg = <0x87900000 0x3E00000>; reg-names = "secapp-region"; memory-region = <&qseecom_mem>; qcom,hlos-num-ce-hw-instances = <1>; @@ -3020,7 +3008,7 @@ qcom_smcinvoke: smcinvoke@87900000 { compatible = "qcom,smcinvoke"; - reg = <0x87900000 0x2200000>; + reg = <0x87900000 0x3E00000>; reg-names = "secapp-region"; }; @@ -3563,7 +3551,7 @@ qcom,rmtfs_sharedmem@0 { compatible = "qcom,sharedmem-uio"; - reg = <0x0 0x200000>; + reg = <0x0 0x300000>; reg-names = "rmtfs"; qcom,client-id = <0x00000001>; qcom,guard-memory; diff --git a/arch/arm64/boot/dts/qcom/xiaomi-sm8150-common.dtsi b/arch/arm64/boot/dts/qcom/xiaomi-sm8150-common.dtsi new file mode 100644 index 000000000000..c603224e08a1 --- /dev/null +++ b/arch/arm64/boot/dts/qcom/xiaomi-sm8150-common.dtsi @@ -0,0 +1,257 @@ +/* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#include +#include + +#include "sm8150-pmic-overlay.dtsi" +#include "sm8150-sde-display.dtsi" +#include "sm8150-thermal-overlay.dtsi" + +&qupv3_se12_2uart { + status = "ok"; +}; + +&vendor { + bluetooth: bt_wcn3990 { + compatible = "qca,wcn3990"; + qca,bt-vdd-core-supply = <&pm8150_l7>; + qca,bt-vdd-pa-supply = <&pm8150l_l2>; + qca,bt-vdd-ldo-supply = <&pm8150l_l11>; + + qca,bt-vdd-core-voltage-level = <1800000 1800000>; + qca,bt-vdd-pa-voltage-level = <1304000 1304000>; + qca,bt-vdd-ldo-voltage-level = <3312000 3312000>; + + qca,bt-vdd-core-current-level = <0>; /* LPM/PFM */ + qca,bt-vdd-pa-current-level = <0>; /* LPM/PFM */ + qca,bt-vdd-ldo-current-level = <0>; /* LPM/PFM */ + }; +}; + +&qupv3_se13_4uart { + status = "ok"; +}; + +&qupv3_se3_spi { + status = "ok"; +}; + +&qupv3_se4_i2c { + status = "ok"; +}; + +&soc { + gpio_keys { + compatible = "gpio-keys"; + label = "gpio-keys"; + + pinctrl-names = "default"; + pinctrl-0 = <&key_vol_up_default>; + + vol_up { + label = "volume_up"; + gpios = <&pm8150_gpios 6 GPIO_ACTIVE_LOW>; + linux,input-type = <1>; + linux,code = ; + gpio-key,wakeup; + debounce-interval = <15>; + linux,can-disable; + }; + + }; + + ext_5v_boost: ext_5v_boost { + compatible = "regulator-fixed"; + status = "disabled"; + regulator-name = "ext_5v_boost"; + gpio = <&pm8150b_gpios 12 GPIO_ACTIVE_HIGH>; + enable-active-high; + regulator-enable-ramp-delay = <1600>; + + pinctrl-names = "default"; + pinctrl-0 = <&otg_vbus_boost_default>; + }; + + wdog: qcom,wdt@17c10000 { + qcom,bark-time = <20000>; + qcom,pet-time = <15000>; + }; +}; + +&dsi_samsung_fhd_ea8076_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <2>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + //qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_samsung_fhd_ea8076_f1_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <2>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + //qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_samsung_fhd_ea8076_f1mp_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <2>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + //qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_samsung_fhd_ea8076_f1p2_2_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <2>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + //qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_samsung_fhd_ea8076_f1p2_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <2>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + //qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_ss_fhd_ea8076_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <2>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + //qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&dsi_ss_fhd_ea8076_global_cmd { + qcom,panel-supply-entries = <&dsi_amoled_panel_pwr_supply>; + qcom,mdss-dsi-bl-pmic-control-type = "bl_ctrl_dcs"; + qcom,mdss-dsi-bl-min-level = <2>; + qcom,mdss-dsi-bl-max-level = <2047>; + qcom,mdss-dsi-mode-sel-gpio-state = "single_port"; + //qcom,panel-mode-gpio = <&tlmm 7 0>; + qcom,platform-te-gpio = <&tlmm 8 0>; + qcom,platform-reset-gpio = <&tlmm 6 0>; +}; + +&qupv3_se9_i2c { + status = "ok"; + nq@28 { + compatible = "qcom,nq-nci"; + reg = <0x28>; + qcom,nq-irq = <&tlmm 47 0x00>; + qcom,nq-ven = <&tlmm 103 0x00>; + qcom,nq-firm = <&tlmm 48 0x00>; + qcom,nq-clkreq = <&tlmm 113 0x00>; + //qcom,nq-esepwr = <&tlmm 42 0x00>; + interrupt-parent = <&tlmm>; + interrupts = <47 0>; + interrupt-names = "nfc_irq"; + pinctrl-names = "nfc_active", "nfc_suspend"; + pinctrl-0 = <&nfc_int_active &nfc_enable_active + &nfc_clk_req_active>; + pinctrl-1 = <&nfc_int_suspend &nfc_enable_suspend + &nfc_clk_req_suspend>; + }; +}; + +&ufsphy_mem { + compatible = "qcom,ufs-phy-qmp-v4"; + + vdda-phy-supply = <&pm8150_l5>; + vdda-phy-always-on; + vdda-pll-supply = <&pm8150l_l3>; + vdda-phy-max-microamp = <90200>; + vdda-pll-max-microamp = <19000>; + + status = "ok"; +}; + +&ufshc_mem { + vdd-hba-supply = <&ufs_phy_gdsc>; + vdd-hba-fixed-regulator; + vcc-supply = <&pm8150_l10>; + vcc-voltage-level = <2950000 2960000>; + vccq2-supply = <&pm8150_s4>; + vcc-max-microamp = <750000>; + vccq2-max-microamp = <750000>; + + qcom,vddp-ref-clk-supply = <&pm8150_l9>; + qcom,vddp-ref-clk-max-microamp = <100>; + + status = "ok"; +}; + +&pm8150b_charger { + io-channels = <&pm8150b_vadc ADC_USB_IN_V_16>, + <&pm8150b_vadc ADC_USB_IN_I>, + <&pm8150b_vadc ADC_CHG_TEMP>; + io-channel-names = "usb_in_voltage", + "usb_in_current", + "chg_temp"; +}; + +&wil6210 { + status = "ok"; +}; + +&mhi_0 { + mhi,fw-name = "debug.mbn"; +}; + +&pcie0 { + status = "disabled"; +}; + +&pcie1 { + status = "disabled"; +}; + +&thermal_zones { + gpuss-1-usr { + status = "disabled"; + }; +}; + +&msm_gpu { + tzone-names = "gpuss-0-usr"; +}; + +&usb2_phy1 { + status = "ok"; +}; + +&usb_qmp_phy { + status = "ok"; +}; diff --git a/arch/arm64/configs/cepheus_defconfig b/arch/arm64/configs/cepheus_defconfig new file mode 100644 index 000000000000..c2450d8a5a29 --- /dev/null +++ b/arch/arm64/configs/cepheus_defconfig @@ -0,0 +1,698 @@ +CONFIG_HOTPLUG_SIZE_BITS=29 +CONFIG_LOCALVERSION="-perf" +# CONFIG_LOCALVERSION_AUTO is not set +# CONFIG_FHANDLE is not set +CONFIG_AUDIT=y +# CONFIG_AUDITSYSCALL is not set +CONFIG_NO_HZ=y +CONFIG_HIGH_RES_TIMERS=y +CONFIG_IRQ_TIME_ACCOUNTING=y +CONFIG_SCHED_WALT=y +CONFIG_TASKSTATS=y +CONFIG_TASK_XACCT=y +CONFIG_TASK_IO_ACCOUNTING=y +CONFIG_RCU_EXPERT=y +CONFIG_RCU_FAST_NO_HZ=y +CONFIG_RCU_NOCB_CPU=y +CONFIG_IKCONFIG=y +CONFIG_IKCONFIG_PROC=y +CONFIG_LOG_CPU_MAX_BUF_SHIFT=17 +CONFIG_MEMCG=y +CONFIG_MEMCG_SWAP=y +CONFIG_BLK_CGROUP=y +CONFIG_RT_GROUP_SCHED=y +CONFIG_CGROUP_FREEZER=y +CONFIG_CPUSETS=y +CONFIG_CGROUP_CPUACCT=y +CONFIG_CGROUP_BPF=y +CONFIG_SCHED_CORE_CTL=y +CONFIG_NAMESPACES=y +# CONFIG_UTS_NS is not set +# CONFIG_PID_NS is not set +CONFIG_SCHED_AUTOGROUP=y +CONFIG_SCHED_TUNE=y +CONFIG_DEFAULT_USE_ENERGY_AWARE=y +CONFIG_BLK_DEV_INITRD=y +# CONFIG_RD_XZ is not set +# CONFIG_RD_LZO is not set +# CONFIG_RD_LZ4 is not set +CONFIG_KALLSYMS_ALL=y +CONFIG_BPF_SYSCALL=y +CONFIG_EMBEDDED=y +# CONFIG_SLUB_DEBUG is not set +# CONFIG_COMPAT_BRK is not set +CONFIG_SLAB_FREELIST_RANDOM=y +CONFIG_SLAB_FREELIST_HARDENED=y +CONFIG_PROFILING=y +CONFIG_JUMP_LABEL=y +CONFIG_CC_STACKPROTECTOR_STRONG=y +CONFIG_REFCOUNT_FULL=y +CONFIG_MODULES=y +CONFIG_MODULE_UNLOAD=y +CONFIG_MODULE_FORCE_UNLOAD=y +CONFIG_MODVERSIONS=y +CONFIG_PARTITION_ADVANCED=y +CONFIG_CFQ_GROUP_IOSCHED=y +CONFIG_ARCH_QCOM=y +CONFIG_ARCH_SM8150=y +CONFIG_PCI=y +CONFIG_PCI_MSM=y +CONFIG_PCI_MSM_MSI=y +CONFIG_SCHED_MC=y +CONFIG_NR_CPUS=8 +CONFIG_PREEMPT=y +CONFIG_HZ_100=y +CONFIG_MEMORY_HOTPLUG=y +CONFIG_MEMORY_HOTPLUG_DEFAULT_ONLINE=y +CONFIG_MEMORY_HOTPLUG_MOVABLE_NODE=y +CONFIG_MEMORY_HOTREMOVE=y +CONFIG_CMA=y +CONFIG_ZSMALLOC=y +CONFIG_BALANCE_ANON_FILE_RECLAIM=y +CONFIG_SECCOMP=y +CONFIG_OKL4_GUEST=y +# CONFIG_HARDEN_BRANCH_PREDICTOR is not set +CONFIG_ARMV8_DEPRECATED=y +CONFIG_SWP_EMULATION=y +CONFIG_CP15_BARRIER_EMULATION=y +CONFIG_SETEND_EMULATION=y +# CONFIG_ARM64_VHE is not set +CONFIG_RANDOMIZE_BASE=y +# CONFIG_EFI is not set +CONFIG_BUILD_ARM64_APPENDED_DTB_IMAGE=y +CONFIG_BUILD_ARM64_UNCOMPRESSED_KERNEL=y +CONFIG_KRYO_PMU_WORKAROUND=y +CONFIG_BUILD_ARM64_DT_OVERLAY=y +# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set +CONFIG_COMPAT=y +CONFIG_SUSPEND_SKIP_SYNC=y +CONFIG_PM_WAKELOCKS=y +CONFIG_PM_WAKELOCKS_LIMIT=0 +# CONFIG_PM_WAKELOCKS_GC is not set +CONFIG_WQ_POWER_EFFICIENT_DEFAULT=y +CONFIG_CPU_IDLE=y +CONFIG_ARM_CPUIDLE=y +CONFIG_CPU_FREQ=y +CONFIG_CPU_FREQ_STAT=y +CONFIG_CPU_FREQ_TIMES=y +CONFIG_CPU_FREQ_GOV_POWERSAVE=y +CONFIG_CPU_FREQ_GOV_USERSPACE=y +CONFIG_CPU_BOOST=y +CONFIG_CPU_FREQ_GOV_SCHEDUTIL=y +CONFIG_NET=y +CONFIG_PACKET=y +CONFIG_UNIX=y +CONFIG_XFRM_USER=y +CONFIG_XFRM_INTERFACE=y +CONFIG_XFRM_STATISTICS=y +CONFIG_NET_KEY=y +CONFIG_INET=y +CONFIG_IP_MULTICAST=y +CONFIG_IP_ADVANCED_ROUTER=y +CONFIG_IP_MULTIPLE_TABLES=y +CONFIG_IP_ROUTE_VERBOSE=y +CONFIG_IP_PNP=y +CONFIG_IP_PNP_DHCP=y +CONFIG_NET_IPGRE_DEMUX=y +CONFIG_SYN_COOKIES=y +CONFIG_NET_IPVTI=y +CONFIG_INET_AH=y +CONFIG_INET_ESP=y +CONFIG_INET_IPCOMP=y +CONFIG_INET_UDP_DIAG=y +CONFIG_INET_DIAG_DESTROY=y +CONFIG_TCP_CONG_ADVANCED=y +CONFIG_TCP_CONG_BBR=y +CONFIG_DEFAULT_BBR=y +CONFIG_IPV6_ROUTER_PREF=y +CONFIG_IPV6_ROUTE_INFO=y +CONFIG_IPV6_OPTIMISTIC_DAD=y +CONFIG_INET6_AH=y +CONFIG_INET6_ESP=y +CONFIG_INET6_IPCOMP=y +CONFIG_IPV6_MIP6=y +CONFIG_IPV6_VTI=y +CONFIG_IPV6_MULTIPLE_TABLES=y +CONFIG_IPV6_SUBTREES=y +CONFIG_NETFILTER=y +CONFIG_NF_CONNTRACK=y +CONFIG_NF_CONNTRACK_SECMARK=y +CONFIG_NF_CONNTRACK_EVENTS=y +CONFIG_NF_CONNTRACK_AMANDA=y +CONFIG_NF_CONNTRACK_FTP=y +CONFIG_NF_CONNTRACK_H323=y +CONFIG_NF_CONNTRACK_IRC=y +CONFIG_NF_CONNTRACK_NETBIOS_NS=y +CONFIG_NF_CONNTRACK_PPTP=y +CONFIG_NF_CONNTRACK_SANE=y +CONFIG_NF_CONNTRACK_TFTP=y +CONFIG_NF_CT_NETLINK=y +CONFIG_NETFILTER_XT_TARGET_CLASSIFY=y +CONFIG_NETFILTER_XT_TARGET_CONNMARK=y +CONFIG_NETFILTER_XT_TARGET_CONNSECMARK=y +CONFIG_NETFILTER_XT_TARGET_IDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_HARDIDLETIMER=y +CONFIG_NETFILTER_XT_TARGET_LOG=y +CONFIG_NETFILTER_XT_TARGET_MARK=y +CONFIG_NETFILTER_XT_TARGET_NFLOG=y +CONFIG_NETFILTER_XT_TARGET_NFQUEUE=y +CONFIG_NETFILTER_XT_TARGET_NOTRACK=y +CONFIG_NETFILTER_XT_TARGET_TEE=y +CONFIG_NETFILTER_XT_TARGET_TPROXY=y +CONFIG_NETFILTER_XT_TARGET_TRACE=y +CONFIG_NETFILTER_XT_TARGET_SECMARK=y +CONFIG_NETFILTER_XT_TARGET_TCPMSS=y +CONFIG_NETFILTER_XT_MATCH_BPF=y +CONFIG_NETFILTER_XT_MATCH_COMMENT=y +CONFIG_NETFILTER_XT_MATCH_CONNLIMIT=y +CONFIG_NETFILTER_XT_MATCH_CONNMARK=y +CONFIG_NETFILTER_XT_MATCH_CONNTRACK=y +CONFIG_NETFILTER_XT_MATCH_DSCP=y +CONFIG_NETFILTER_XT_MATCH_ESP=y +CONFIG_NETFILTER_XT_MATCH_HASHLIMIT=y +CONFIG_NETFILTER_XT_MATCH_HELPER=y +CONFIG_NETFILTER_XT_MATCH_IPRANGE=y +# CONFIG_NETFILTER_XT_MATCH_L2TP is not set +CONFIG_NETFILTER_XT_MATCH_LENGTH=y +CONFIG_NETFILTER_XT_MATCH_LIMIT=y +CONFIG_NETFILTER_XT_MATCH_MAC=y +CONFIG_NETFILTER_XT_MATCH_MARK=y +CONFIG_NETFILTER_XT_MATCH_MULTIPORT=y +CONFIG_NETFILTER_XT_MATCH_OWNER=y +CONFIG_NETFILTER_XT_MATCH_POLICY=y +CONFIG_NETFILTER_XT_MATCH_PKTTYPE=y +CONFIG_NETFILTER_XT_MATCH_QUOTA=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2=y +CONFIG_NETFILTER_XT_MATCH_QUOTA2_LOG=y +# CONFIG_NETFILTER_XT_MATCH_SCTP is not set +CONFIG_NETFILTER_XT_MATCH_SOCKET=y +CONFIG_NETFILTER_XT_MATCH_STATE=y +CONFIG_NETFILTER_XT_MATCH_STATISTIC=y +CONFIG_NETFILTER_XT_MATCH_STRING=y +CONFIG_NETFILTER_XT_MATCH_TIME=y +CONFIG_NETFILTER_XT_MATCH_U32=y +CONFIG_NF_CONNTRACK_IPV4=y +CONFIG_NF_SOCKET_IPV4=y +CONFIG_IP_NF_IPTABLES=y +CONFIG_IP_NF_MATCH_AH=y +CONFIG_IP_NF_MATCH_ECN=y +CONFIG_IP_NF_MATCH_RPFILTER=y +CONFIG_IP_NF_MATCH_TTL=y +CONFIG_IP_NF_FILTER=y +CONFIG_IP_NF_TARGET_REJECT=y +CONFIG_IP_NF_NAT=y +CONFIG_IP_NF_TARGET_MASQUERADE=y +CONFIG_IP_NF_TARGET_NETMAP=y +CONFIG_IP_NF_TARGET_REDIRECT=y +CONFIG_IP_NF_MANGLE=y +CONFIG_IP_NF_RAW=y +CONFIG_IP_NF_SECURITY=y +CONFIG_IP_NF_ARPTABLES=y +CONFIG_IP_NF_ARPFILTER=y +CONFIG_IP_NF_ARP_MANGLE=y +CONFIG_NF_CONNTRACK_IPV6=y +CONFIG_NF_SOCKET_IPV6=y +CONFIG_IP6_NF_IPTABLES=y +CONFIG_IP6_NF_MATCH_RPFILTER=y +CONFIG_IP6_NF_FILTER=y +CONFIG_IP6_NF_TARGET_REJECT=y +CONFIG_IP6_NF_MANGLE=y +CONFIG_IP6_NF_RAW=y +CONFIG_BRIDGE_NF_EBTABLES=y +CONFIG_BRIDGE_EBT_BROUTE=y +CONFIG_IP_SCTP=y +CONFIG_L2TP=y +CONFIG_L2TP_V3=y +CONFIG_L2TP_IP=y +CONFIG_L2TP_ETH=y +CONFIG_BRIDGE=y +CONFIG_NET_SCHED=y +CONFIG_NET_SCH_HTB=y +CONFIG_NET_SCH_PRIO=y +CONFIG_NET_SCH_MULTIQ=y +CONFIG_NET_SCH_INGRESS=y +CONFIG_NET_CLS_FW=y +CONFIG_NET_CLS_U32=y +CONFIG_CLS_U32_MARK=y +CONFIG_NET_CLS_FLOW=y +CONFIG_NET_CLS_BPF=y +CONFIG_NET_EMATCH=y +CONFIG_NET_EMATCH_CMP=y +CONFIG_NET_EMATCH_NBYTE=y +CONFIG_NET_EMATCH_U32=y +CONFIG_NET_EMATCH_META=y +CONFIG_NET_EMATCH_TEXT=y +CONFIG_NET_CLS_ACT=y +CONFIG_NET_ACT_GACT=y +CONFIG_NET_ACT_MIRRED=y +CONFIG_NET_ACT_SKBEDIT=y +CONFIG_NET_SWITCHDEV=y +CONFIG_QRTR=y +CONFIG_QRTR_SMD=y +CONFIG_QRTR_MHI=y +CONFIG_SOCKEV_NLMCAST=y +CONFIG_BT=y +CONFIG_MSM_BT_POWER=y +CONFIG_CFG80211=y +CONFIG_CFG80211_CERTIFICATION_ONUS=y +CONFIG_CFG80211_REG_CELLULAR_HINTS=y +CONFIG_CFG80211_INTERNAL_REGDB=y +CONFIG_RFKILL=y +CONFIG_NFC_NQ=y +CONFIG_FW_LOADER_USER_HELPER_FALLBACK=y +CONFIG_REGMAP_ALLOW_WRITE_DEBUGFS=y +CONFIG_DMA_CMA=y +CONFIG_MHI_BUS=y +CONFIG_MHI_QCOM=y +CONFIG_MHI_NETDEV=y +CONFIG_MHI_UCI=y +CONFIG_ZRAM=y +CONFIG_BLK_DEV_LOOP=y +CONFIG_BLK_DEV_LOOP_MIN_COUNT=16 +CONFIG_BLK_DEV_RAM=y +CONFIG_BLK_DEV_RAM_SIZE=8192 +CONFIG_HDCP_QSEECOM=y +CONFIG_QSEECOM=y +CONFIG_UID_SYS_STATS=y +CONFIG_MEMORY_STATE_TIME=y +CONFIG_OKL4_USER_VIRQ=y +CONFIG_SCSI=y +CONFIG_BLK_DEV_SD=y +CONFIG_CHR_DEV_SG=y +CONFIG_CHR_DEV_SCH=y +CONFIG_SCSI_CONSTANTS=y +CONFIG_SCSI_SCAN_ASYNC=y +CONFIG_SCSI_UFSHCD=y +CONFIG_SCSI_UFSHCD_PLATFORM=y +CONFIG_SCSI_UFS_QCOM=y +CONFIG_SCSI_UFS_QCOM_ICE=y +CONFIG_MD=y +CONFIG_BLK_DEV_DM=y +CONFIG_DM_CRYPT=y +CONFIG_DM_DEFAULT_KEY=y +CONFIG_DM_UEVENT=y +CONFIG_DM_VERITY=y +CONFIG_DM_VERITY_FEC=y +CONFIG_DM_BOW=y +CONFIG_NETDEVICES=y +CONFIG_BONDING=y +CONFIG_DUMMY=y +CONFIG_TUN=y +CONFIG_SKY2=y +CONFIG_RMNET=y +CONFIG_SMSC911X=y +CONFIG_PPP=y +CONFIG_PPP_BSDCOMP=y +CONFIG_PPP_DEFLATE=y +CONFIG_PPP_FILTER=y +CONFIG_PPP_MPPE=y +CONFIG_PPP_MULTILINK=y +CONFIG_PPPOE=y +CONFIG_PPTP=y +CONFIG_PPPOL2TP=y +CONFIG_PPPOLAC=y +CONFIG_PPPOPNS=y +CONFIG_PPP_ASYNC=y +CONFIG_PPP_SYNC_TTY=y +CONFIG_USB_RTL8152=y +CONFIG_USB_LAN78XX=y +CONFIG_USB_USBNET=y +CONFIG_WCNSS_MEM_PRE_ALLOC=y +CONFIG_CLD_LL_CORE=y +CONFIG_CNSS_GENL=y +CONFIG_INPUT_EVDEV=y +CONFIG_KEYBOARD_GPIO=y +# CONFIG_INPUT_MOUSE is not set +CONFIG_INPUT_TOUCHSCREEN=y +CONFIG_TOUCHSCREEN_ST_FTS_V521=y +CONFIG_FTS_FOD_AREA_REPORT=y +CONFIG_TOUCHSCREEN_ST_DEBUG_FS=y +CONFIG_I2C_BY_DMA=y +CONFIG_INPUT_MISC=y +CONFIG_INPUT_QPNP_POWER_ON=y +CONFIG_INPUT_QTI_HAPTICS=y +CONFIG_INPUT_UINPUT=y +CONFIG_INPUT_FINGERPRINT=y +CONFIG_FINGERPRINT_GOODIX_TA=y +# CONFIG_SERIO_SERPORT is not set +# CONFIG_VT is not set +# CONFIG_LEGACY_PTYS is not set +# CONFIG_DEVMEM is not set +CONFIG_SERIAL_MSM_GENI=y +CONFIG_HW_RANDOM=y +CONFIG_HW_RANDOM_MSM_LEGACY=y +# CONFIG_DEVPORT is not set +CONFIG_DIAG_CHAR=y +CONFIG_MSM_FASTCVPD=y +CONFIG_MSM_ADSPRPC=y +CONFIG_OKL4_PIPE=y +CONFIG_I2C_CHARDEV=y +CONFIG_I2C_QCOM_GENI=y +CONFIG_SPI=y +CONFIG_SPI_QCOM_GENI=y +CONFIG_SPI_SPIDEV=y +CONFIG_SPMI=y +CONFIG_SPMI_MSM_PMIC_ARB_DEBUG=y +CONFIG_SPMI_SIMULATOR=y +CONFIG_PM8150_PMIC_SIMULATOR=y +CONFIG_PM8150B_PMIC_SIMULATOR=y +CONFIG_PM8150L_PMIC_SIMULATOR=y +CONFIG_SLIMBUS_MSM_NGD=y +CONFIG_PINCTRL_QCOM_SPMI_PMIC=y +CONFIG_PINCTRL_SM8150=y +CONFIG_GPIO_SYSFS=y +CONFIG_POWER_RESET_QCOM=y +CONFIG_QCOM_DLOAD_MODE=y +CONFIG_POWER_RESET_XGENE=y +CONFIG_POWER_RESET_SYSCON=y +CONFIG_QPNP_FG_GEN4=y +CONFIG_IDT_P9220=y +CONFIG_QPNP_SMB5=y +CONFIG_QPNP_QNOVO5=y +CONFIG_SMB1390_CHARGE_PUMP=y +CONFIG_THERMAL=y +CONFIG_THERMAL_WRITABLE_TRIPS=y +CONFIG_THERMAL_GOV_USER_SPACE=y +CONFIG_THERMAL_GOV_LOW_LIMITS=y +CONFIG_CPU_THERMAL=y +CONFIG_DEVFREQ_THERMAL=y +CONFIG_QCOM_SPMI_TEMP_ALARM=y +CONFIG_THERMAL_TSENS=y +CONFIG_QTI_THERMAL_LIMITS_DCVS=y +CONFIG_QTI_VIRTUAL_SENSOR=y +CONFIG_QTI_AOP_REG_COOLING_DEVICE=y +CONFIG_QTI_QMI_COOLING_DEVICE=y +CONFIG_QTI_QMI_SENSOR=y +CONFIG_REGULATOR_COOLING_DEVICE=y +CONFIG_QTI_BCL_PMIC5=y +CONFIG_QTI_BCL_SOC_DRIVER=y +CONFIG_QTI_ADC_TM=y +CONFIG_MFD_I2C_PMIC=y +CONFIG_MFD_SPMI_PMIC=y +CONFIG_REGULATOR_FIXED_VOLTAGE=y +CONFIG_REGULATOR_PROXY_CONSUMER=y +CONFIG_REGULATOR_QPNP_AMOLED=y +CONFIG_REGULATOR_QPNP_LCDB=y +CONFIG_REGULATOR_REFGEN=y +CONFIG_REGULATOR_RPMH=y +CONFIG_REGULATOR_STUB=y +CONFIG_LIRC=y +CONFIG_RC_DEVICES=y +CONFIG_IR_SPI=y +CONFIG_MEDIA_SUPPORT=y +CONFIG_MEDIA_CAMERA_SUPPORT=y +CONFIG_MEDIA_DIGITAL_TV_SUPPORT=y +CONFIG_MEDIA_CONTROLLER=y +CONFIG_VIDEO_V4L2_SUBDEV_API=y +CONFIG_VIDEO_ADV_DEBUG=y +CONFIG_VIDEO_FIXED_MINOR_RANGES=y +CONFIG_MEDIA_USB_SUPPORT=y +CONFIG_USB_VIDEO_CLASS=y +CONFIG_V4L_PLATFORM_DRIVERS=y +CONFIG_SPECTRA_CAMERA=y +CONFIG_VCM_AK7374=y +CONFIG_MSM_VIDC_V4L2=y +CONFIG_MSM_VIDC_GOVERNORS=y +CONFIG_MSM_SDE_ROTATOR=y +CONFIG_MSM_SDE_ROTATOR_EVTLOG_DEBUG=y +CONFIG_MSM_NPU=y +CONFIG_TSPP=y +CONFIG_DRM=y +CONFIG_DRM_MSM_REGISTER_LOGGING=y +CONFIG_DRM_SDE_EVTLOG_DEBUG=y +CONFIG_DRM_SDE_RSC=y +CONFIG_DRM_LT_LT9611=y +CONFIG_FB_ARMCLCD=y +CONFIG_BACKLIGHT_QCOM_SPMI_WLED=y +CONFIG_LOGO=y +# CONFIG_LOGO_LINUX_MONO is not set +# CONFIG_LOGO_LINUX_VGA16 is not set +CONFIG_SOUND=y +CONFIG_SND=y +CONFIG_SND_DYNAMIC_MINORS=y +CONFIG_SND_USB_AUDIO=y +CONFIG_SND_USB_AUDIO_QMI=y +CONFIG_SND_SOC=y +CONFIG_UHID=y +CONFIG_HID_APPLE=y +CONFIG_HID_ELECOM=y +CONFIG_HID_MAGICMOUSE=y +CONFIG_HID_MICROSOFT=y +CONFIG_HID_MULTITOUCH=y +CONFIG_HID_PLANTRONICS=y +CONFIG_HID_SONY=y +CONFIG_HID_QVR=y +CONFIG_USB=y +CONFIG_USB_ANNOUNCE_NEW_DEVICES=y +CONFIG_USB_XHCI_HCD=y +CONFIG_USB_EHCI_HCD=y +CONFIG_USB_EHCI_HCD_PLATFORM=y +CONFIG_USB_OHCI_HCD=y +CONFIG_USB_OHCI_HCD_PLATFORM=y +CONFIG_USB_STORAGE=y +CONFIG_USB_DWC3=y +CONFIG_USB_DWC3_MSM=y +CONFIG_USB_ISP1760=y +CONFIG_USB_ISP1760_HOST_ROLE=y +CONFIG_USB_EHSET_TEST_FIXTURE=y +CONFIG_USB_LINK_LAYER_TEST=y +CONFIG_USB_REDRIVER_NB7VPQ904M=y +CONFIG_NOP_USB_XCEIV=y +CONFIG_USB_QCOM_EMU_PHY=y +CONFIG_USB_MSM_SSPHY_QMP=y +CONFIG_MSM_HSUSB_PHY=y +CONFIG_DUAL_ROLE_USB_INTF=y +CONFIG_USB_GADGET=y +CONFIG_USB_GADGET_VBUS_DRAW=900 +CONFIG_USB_CONFIGFS=y +CONFIG_USB_CONFIGFS_NCM=y +CONFIG_USB_CONFIGFS_RNDIS=y +CONFIG_USB_CONFIGFS_MASS_STORAGE=y +CONFIG_USB_CONFIGFS_F_FS=y +CONFIG_USB_CONFIGFS_F_MTP=y +CONFIG_USB_CONFIGFS_F_PTP=y +CONFIG_USB_CONFIGFS_F_ACC=y +CONFIG_USB_CONFIGFS_F_AUDIO_SRC=y +CONFIG_USB_CONFIGFS_UEVENT=y +CONFIG_USB_CONFIGFS_F_UAC2=y +CONFIG_USB_CONFIGFS_F_MIDI=y +CONFIG_USB_CONFIGFS_F_HID=y +CONFIG_USB_CONFIGFS_F_DIAG=y +CONFIG_USB_CONFIGFS_F_CDEV=y +CONFIG_USB_CONFIGFS_F_CCID=y +CONFIG_USB_CONFIGFS_F_GSI=y +CONFIG_USB_CONFIGFS_F_QDSS=y +CONFIG_USB_PD_POLICY=y +CONFIG_QPNP_USB_PDPHY=y +CONFIG_NEW_LEDS=y +CONFIG_LEDS_CLASS=y +CONFIG_LEDS_QPNP_FLASH_V2=y +CONFIG_LEDS_QPNP_HAPTICS=y +CONFIG_LEDS_QTI_TRI_LED=y +CONFIG_LEDS_TRIGGER_TIMER=y +CONFIG_EDAC=y +CONFIG_EDAC_KRYO_ARM64=y +CONFIG_EDAC_KRYO_ARM64_PANIC_ON_UE=y +CONFIG_RTC_CLASS=y +CONFIG_RTC_DRV_QPNP=y +CONFIG_DMADEVICES=y +CONFIG_QCOM_GPI_DMA=y +CONFIG_UIO=y +CONFIG_UIO_MSM_SHAREDMEM=y +CONFIG_STAGING=y +CONFIG_ASHMEM=y +CONFIG_ANDROID_LOW_MEMORY_KILLER=y +CONFIG_ION=y +CONFIG_QCA_CLD_WLAN=m +CONFIG_QCOM_GENI_SE=y +CONFIG_QPNP_REVID=y +CONFIG_SPS=y +CONFIG_SPS_SUPPORT_NDP_BAM=y +CONFIG_USB_BAM=y +CONFIG_IPA3=y +CONFIG_IPA_WDI_UNIFIED_API=y +CONFIG_RMNET_IPA3=y +CONFIG_RNDIS_IPA=y +CONFIG_IPA3_MHI_PROXY=y +CONFIG_IPA3_MHI_PRIME_MANAGER=y +CONFIG_IPA_UT=y +CONFIG_SEEMP_CORE=y +CONFIG_QCOM_MDSS_PLL=y +CONFIG_SPMI_PMIC_CLKDIV=y +CONFIG_MSM_CLK_AOP_QMP=y +CONFIG_MSM_GCC_SM8150=y +CONFIG_MSM_NPUCC_SM8150=y +CONFIG_MSM_VIDEOCC_SM8150=y +CONFIG_MSM_CAMCC_SM8150=y +CONFIG_CLOCK_CPU_OSM=y +CONFIG_MSM_DISPCC_SM8150=y +CONFIG_MSM_DEBUGCC_SM8150=y +CONFIG_MSM_CLK_RPMH=y +CONFIG_MSM_GPUCC_SM8150=y +CONFIG_HWSPINLOCK=y +CONFIG_HWSPINLOCK_QCOM=y +CONFIG_QCOM_APCS_IPC=y +CONFIG_MSM_QMP=y +CONFIG_IOMMU_IO_PGTABLE_FAST=y +CONFIG_ARM_SMMU=y +CONFIG_QCOM_LAZY_MAPPING=y +CONFIG_IOMMU_DEBUG=y +CONFIG_IOMMU_DEBUG_TRACKING=y +CONFIG_IOMMU_TESTS=y +CONFIG_RPMSG_CHAR=y +CONFIG_RPMSG_QCOM_GLINK_SMEM=y +CONFIG_RPMSG_QCOM_GLINK_SPSS=y +CONFIG_RPMSG_QCOM_GLINK_SPI=y +CONFIG_QCOM_MEM_OFFLINE=y +CONFIG_OVERRIDE_MEMORY_LIMIT=y +CONFIG_QCOM_CPUSS_DUMP=y +CONFIG_QCOM_RUN_QUEUE_STATS=y +CONFIG_QCOM_LLCC=y +CONFIG_QCOM_SM8150_LLCC=y +CONFIG_QCOM_QMI_HELPERS=y +CONFIG_QCOM_QMI_RMNET=y +CONFIG_QCOM_QMI_DFC=y +CONFIG_QCOM_QMI_POWER_COLLAPSE=y +CONFIG_QCOM_SMEM=y +CONFIG_QCOM_MEMORY_DUMP_V2=y +CONFIG_QCOM_WATCHDOG_V2=y +CONFIG_QCOM_FORCE_WDOG_BITE_ON_PANIC=y +CONFIG_QCOM_SMP2P=y +CONFIG_QPNP_PBS=y +CONFIG_MSM_SERVICE_LOCATOR=y +CONFIG_MSM_SERVICE_NOTIFIER=y +CONFIG_MSM_SUBSYSTEM_RESTART=y +CONFIG_MSM_PIL=y +CONFIG_MSM_SYSMON_QMI_COMM=y +CONFIG_MSM_PIL_SSR_GENERIC=y +CONFIG_SETUP_SSR_NOTIF_TIMEOUTS=y +CONFIG_SSR_SYSMON_NOTIF_TIMEOUT=20000 +CONFIG_SSR_SUBSYS_NOTIF_TIMEOUT=20000 +CONFIG_PANIC_ON_SSR_NOTIF_TIMEOUT=y +CONFIG_MSM_BOOT_STATS=y +CONFIG_QCOM_DCC_V2=y +CONFIG_QCOM_SECURE_BUFFER=y +CONFIG_ICNSS=y +CONFIG_ICNSS_QMI=y +CONFIG_QCOM_EUD=y +CONFIG_QCOM_MINIDUMP=y +CONFIG_QCOM_BUS_SCALING=y +CONFIG_QCOM_BUS_CONFIG_RPMH=y +CONFIG_QCOM_COMMAND_DB=y +CONFIG_QCOM_EARLY_RANDOM=y +CONFIG_MSM_SPSS_UTILS=y +CONFIG_MSM_SPCOM=y +CONFIG_QTI_RPMH_API=y +CONFIG_QSEE_IPC_IRQ_BRIDGE=y +CONFIG_QCOM_GLINK=y +CONFIG_QCOM_GLINK_PKT=y +CONFIG_QCOM_QDSS_BRIDGE=y +CONFIG_QTI_RPM_STATS_LOG=y +CONFIG_MSM_CDSP_LOADER=y +CONFIG_QCOM_SMCINVOKE=y +CONFIG_MSM_EVENT_TIMER=y +CONFIG_MSM_PM=y +CONFIG_QCOM_FSA4480_I2C=y +CONFIG_MEM_SHARE_QMI_SERVICE=y +CONFIG_MSM_PERFORMANCE=y +CONFIG_QMP_DEBUGFS_CLIENT=y +CONFIG_QCOM_SMP2P_SLEEPSTATE=y +CONFIG_QCOM_CDSP_RM=y +CONFIG_QCOM_AOP_DDR_MESSAGING=y +CONFIG_QCOM_AOP_DDRSS_COMMANDS=y +CONFIG_QCOM_HYP_CORE_CTL=y +CONFIG_DEVFREQ_GOV_PASSIVE=y +CONFIG_QCOM_BIMC_BWMON=y +CONFIG_ARM_MEMLAT_MON=y +CONFIG_QCOMCCI_HWMON=y +CONFIG_QCOM_M4M_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_BW_HWMON=y +CONFIG_DEVFREQ_GOV_QCOM_CACHE_HWMON=y +CONFIG_DEVFREQ_GOV_MEMLAT=y +CONFIG_DEVFREQ_SIMPLE_DEV=y +CONFIG_QCOM_DEVFREQ_DEVBW=y +CONFIG_DEVFREQ_GOV_CDSPL3=y +CONFIG_EXTCON_USB_GPIO=y +CONFIG_IIO=y +CONFIG_QCOM_SPMI_ADC5=y +CONFIG_PWM=y +CONFIG_PWM_QTI_LPG=y +CONFIG_QCOM_KGSL=y +CONFIG_ARM_GIC_V3_ACL=y +CONFIG_QCOM_LLCC_PMU=y +CONFIG_RAS=y +CONFIG_ANDROID=y +CONFIG_ANDROID_BINDER_IPC=y +CONFIG_NVMEM_SPMI_SDAM=y +CONFIG_STM=y +CONFIG_SENSORS_SSC=y +CONFIG_ESOC=y +CONFIG_ESOC_DEV=y +CONFIG_ESOC_CLIENT=y +CONFIG_ESOC_MDM_4x=y +CONFIG_ESOC_MDM_DRV=y +CONFIG_ESOC_MDM_DBG_ENG=y +CONFIG_MSM_TZ_LOG=y +CONFIG_EXT4_FS=y +CONFIG_EXT4_FS_SECURITY=y +CONFIG_EXT4_ENCRYPTION=y +CONFIG_EXT4_FS_ENCRYPTION=y +CONFIG_EXT4_FS_ICE_ENCRYPTION=y +CONFIG_F2FS_FS=y +CONFIG_F2FS_FS_SECURITY=y +CONFIG_F2FS_FS_ENCRYPTION=y +CONFIG_QUOTA=y +CONFIG_QUOTA_NETLINK_INTERFACE=y +CONFIG_QFMT_V2=y +CONFIG_FUSE_FS=y +CONFIG_OVERLAY_FS=y +CONFIG_MSDOS_FS=y +CONFIG_VFAT_FS=y +CONFIG_TMPFS_POSIX_ACL=y +CONFIG_ECRYPT_FS=y +CONFIG_ECRYPT_FS_MESSAGING=y +CONFIG_SDCARD_FS=y +CONFIG_PSTORE=y +CONFIG_PSTORE_CONSOLE=y +CONFIG_PSTORE_PMSG=y +CONFIG_PSTORE_RAM=y +CONFIG_NLS_CODEPAGE_437=y +CONFIG_NLS_ISO8859_1=y +CONFIG_PRINTK_TIME=y +CONFIG_DEBUG_INFO=y +CONFIG_FRAME_WARN=8192 +CONFIG_PAGE_OWNER=y +CONFIG_MAGIC_SYSRQ=y +CONFIG_PANIC_TIMEOUT=-1 +# CONFIG_SCHED_DEBUG is not set +# CONFIG_DEBUG_PREEMPT is not set +CONFIG_IPC_LOGGING=y +# CONFIG_FTRACE is not set +CONFIG_DEBUG_ALIGN_RODATA=y +CONFIG_PFK=y +CONFIG_PFK_WRAPPED_KEY_SUPPORTED=y +CONFIG_SECURITY_PERF_EVENTS_RESTRICT=y +CONFIG_SECURITY=y +CONFIG_HARDENED_USERCOPY=y +CONFIG_FORTIFY_SOURCE=y +CONFIG_SECURITY_SELINUX=y +CONFIG_SECURITY_SMACK=y +CONFIG_CRYPTO_GCM=y +CONFIG_CRYPTO_XCBC=y +CONFIG_CRYPTO_MD4=y +CONFIG_CRYPTO_SHA512=y +CONFIG_CRYPTO_TWOFISH=y +CONFIG_CRYPTO_ANSI_CPRNG=y +CONFIG_CRYPTO_DEV_QCOM_MSM_QCE=y +CONFIG_CRYPTO_DEV_QCRYPTO=y +CONFIG_CRYPTO_DEV_QCEDEV=y +CONFIG_CRYPTO_DEV_QCOM_ICE=y +CONFIG_ARM64_CRYPTO=y +CONFIG_CRYPTO_SHA1_ARM64_CE=y +CONFIG_CRYPTO_SHA2_ARM64_CE=y +CONFIG_CRYPTO_GHASH_ARM64_CE=y +CONFIG_CRYPTO_AES_ARM64_CE_CCM=y +CONFIG_CRYPTO_AES_ARM64_CE_BLK=y +CONFIG_CRYPTO_AES_ARM64_NEON_BLK=y +CONFIG_STACK_HASH_ORDER_SHIFT=12 +CONFIG_MACH_XIAOMI_CEPHEUS=y diff --git a/arch/arm64/include/asm/smp.h b/arch/arm64/include/asm/smp.h index f82b447bd34f..b58ea9338f4e 100644 --- a/arch/arm64/include/asm/smp.h +++ b/arch/arm64/include/asm/smp.h @@ -95,14 +95,7 @@ extern void secondary_entry(void); extern void arch_send_call_function_single_ipi(int cpu); extern void arch_send_call_function_ipi_mask(const struct cpumask *mask); -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL extern void arch_send_wakeup_ipi_mask(const struct cpumask *mask); -#else -static inline void arch_send_wakeup_ipi_mask(const struct cpumask *mask) -{ - BUILD_BUG(); -} -#endif extern int __cpu_disable(void); diff --git a/arch/arm64/include/asm/string.h b/arch/arm64/include/asm/string.h index dd95d33a5bd5..03a6c256b7ec 100644 --- a/arch/arm64/include/asm/string.h +++ b/arch/arm64/include/asm/string.h @@ -16,6 +16,7 @@ #ifndef __ASM_STRING_H #define __ASM_STRING_H +#ifndef CONFIG_KASAN #define __HAVE_ARCH_STRRCHR extern char *strrchr(const char *, int c); @@ -34,6 +35,13 @@ extern __kernel_size_t strlen(const char *); #define __HAVE_ARCH_STRNLEN extern __kernel_size_t strnlen(const char *, __kernel_size_t); +#define __HAVE_ARCH_MEMCMP +extern int memcmp(const void *, const void *, size_t); + +#define __HAVE_ARCH_MEMCHR +extern void *memchr(const void *, int, __kernel_size_t); +#endif + #define __HAVE_ARCH_MEMCPY extern void *memcpy(void *, const void *, __kernel_size_t); extern void *__memcpy(void *, const void *, __kernel_size_t); @@ -42,16 +50,10 @@ extern void *__memcpy(void *, const void *, __kernel_size_t); extern void *memmove(void *, const void *, __kernel_size_t); extern void *__memmove(void *, const void *, __kernel_size_t); -#define __HAVE_ARCH_MEMCHR -extern void *memchr(const void *, int, __kernel_size_t); - #define __HAVE_ARCH_MEMSET extern void *memset(void *, int, __kernel_size_t); extern void *__memset(void *, int, __kernel_size_t); -#define __HAVE_ARCH_MEMCMP -extern int memcmp(const void *, const void *, size_t); - #ifdef CONFIG_ARCH_HAS_UACCESS_FLUSHCACHE #define __HAVE_ARCH_MEMCPY_FLUSHCACHE void memcpy_flushcache(void *dst, const void *src, size_t cnt); diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile index 031c211bb69c..7702f27bfcdf 100644 --- a/arch/arm64/kernel/Makefile +++ b/arch/arm64/kernel/Makefile @@ -34,8 +34,7 @@ arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o arm64-obj-$(CONFIG_ARM64_MODULE_PLTS) += module-plts.o arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o -arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_trace_counters.o \ - perf_trace_user.o +arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o arm64-obj-$(CONFIG_CPU_PM) += sleep.o suspend.o arm64-obj-$(CONFIG_CPU_IDLE) += cpuidle.o diff --git a/arch/arm64/kernel/arm64ksyms.c b/arch/arm64/kernel/arm64ksyms.c index ca1cf2d2b493..1eacbf85d635 100644 --- a/arch/arm64/kernel/arm64ksyms.c +++ b/arch/arm64/kernel/arm64ksyms.c @@ -45,20 +45,23 @@ EXPORT_SYMBOL(__arch_copy_in_user); EXPORT_SYMBOL(memstart_addr); /* string / mem functions */ +#ifndef CONFIG_KASAN EXPORT_SYMBOL(strchr); EXPORT_SYMBOL(strrchr); EXPORT_SYMBOL(strcmp); EXPORT_SYMBOL(strncmp); EXPORT_SYMBOL(strlen); EXPORT_SYMBOL(strnlen); +EXPORT_SYMBOL(memcmp); +EXPORT_SYMBOL(memchr); +#endif + EXPORT_SYMBOL(memset); EXPORT_SYMBOL(memcpy); EXPORT_SYMBOL(memmove); EXPORT_SYMBOL(__memset); EXPORT_SYMBOL(__memcpy); EXPORT_SYMBOL(__memmove); -EXPORT_SYMBOL(memchr); -EXPORT_SYMBOL(memcmp); /* atomic bitops */ EXPORT_SYMBOL(set_bit); diff --git a/arch/arm64/kernel/perf_trace_counters.c b/arch/arm64/kernel/perf_trace_counters.c deleted file mode 100644 index 47983480326e..000000000000 --- a/arch/arm64/kernel/perf_trace_counters.c +++ /dev/null @@ -1,178 +0,0 @@ -/* Copyright (c) 2013-2014, 2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only 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. - */ -#include -#include -#include -#include -#include -#define CREATE_TRACE_POINTS -#include "perf_trace_counters.h" - -static unsigned int tp_pid_state; - -DEFINE_PER_CPU(u32, cntenset_val); -DEFINE_PER_CPU(u32, previous_ccnt); -DEFINE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts); -DEFINE_PER_CPU(u32, old_pid); -DEFINE_PER_CPU(u32, hotplug_flag); - -#define USE_CPUHP_STATE CPUHP_AP_ONLINE - -static int tracectr_cpu_hotplug_coming_up(unsigned int cpu) -{ - per_cpu(hotplug_flag, cpu) = 1; - - return 0; -} - -static void setup_prev_cnts(u32 cpu, u32 cnten_val) -{ - int i; - - if (cnten_val & CC) - per_cpu(previous_ccnt, cpu) = - read_sysreg(pmccntr_el0); - - for (i = 0; i < NUM_L1_CTRS; i++) { - if (cnten_val & (1 << i)) { - /* Select */ - write_sysreg(i, pmselr_el0); - isb(); - /* Read value */ - per_cpu(previous_l1_cnts[i], cpu) = - read_sysreg(pmxevcntr_el0); - } - } -} - -void tracectr_notifier(void *ignore, bool preempt, - struct task_struct *prev, struct task_struct *next) -{ - u32 cnten_val; - int current_pid; - u32 cpu = task_cpu(next); - - if (tp_pid_state != 1) - return; - current_pid = next->pid; - if (per_cpu(old_pid, cpu) != -1) { - cnten_val = read_sysreg(pmcntenset_el0); - per_cpu(cntenset_val, cpu) = cnten_val; - /* Disable all the counters that were enabled */ - write_sysreg(cnten_val, pmcntenclr_el0); - - if (per_cpu(hotplug_flag, cpu) == 1) { - per_cpu(hotplug_flag, cpu) = 0; - setup_prev_cnts(cpu, cnten_val); - } else { - trace_sched_switch_with_ctrs(per_cpu(old_pid, cpu), - current_pid); - } - - /* Enable all the counters that were disabled */ - write_sysreg(cnten_val, pmcntenset_el0); - } - per_cpu(old_pid, cpu) = current_pid; -} - -static void enable_tp_pid(void) -{ - if (tp_pid_state == 0) { - tp_pid_state = 1; - register_trace_sched_switch(tracectr_notifier, NULL); - } -} - -static void disable_tp_pid(void) -{ - if (tp_pid_state == 1) { - tp_pid_state = 0; - unregister_trace_sched_switch(tracectr_notifier, NULL); - } -} - -static ssize_t read_enabled_perftp_file_bool(struct file *file, - char __user *user_buf, size_t count, loff_t *ppos) -{ - char buf[2]; - - buf[1] = '\n'; - if (tp_pid_state == 0) - buf[0] = '0'; - else - buf[0] = '1'; - return simple_read_from_buffer(user_buf, count, ppos, buf, 2); -} - -static ssize_t write_enabled_perftp_file_bool(struct file *file, - const char __user *user_buf, size_t count, loff_t *ppos) -{ - char buf[32]; - size_t buf_size; - - buf[0] = 0; - buf_size = min(count, (sizeof(buf)-1)); - if (copy_from_user(buf, user_buf, buf_size)) - return -EFAULT; - switch (buf[0]) { - case 'y': - case 'Y': - case '1': - enable_tp_pid(); - break; - case 'n': - case 'N': - case '0': - disable_tp_pid(); - break; - } - - return count; -} - -static const struct file_operations fops_perftp = { - .read = read_enabled_perftp_file_bool, - .write = write_enabled_perftp_file_bool, - .llseek = default_llseek, -}; - -int __init init_tracecounters(void) -{ - struct dentry *dir; - struct dentry *file; - unsigned int value = 1; - int cpu, rc; - - dir = debugfs_create_dir("perf_debug_tp", NULL); - if (!dir) - return -ENOMEM; - file = debugfs_create_file("enabled", 0660, dir, - &value, &fops_perftp); - if (!file) { - debugfs_remove(dir); - return -ENOMEM; - } - for_each_possible_cpu(cpu) - per_cpu(old_pid, cpu) = -1; - rc = cpuhp_setup_state_nocalls(USE_CPUHP_STATE, - "tracectr_cpu_hotplug", - tracectr_cpu_hotplug_coming_up, - NULL); - return 0; -} - -int __exit exit_tracecounters(void) -{ - cpuhp_remove_state_nocalls(USE_CPUHP_STATE); - return 0; -} -late_initcall(init_tracecounters); diff --git a/arch/arm64/kernel/perf_trace_counters.h b/arch/arm64/kernel/perf_trace_counters.h deleted file mode 100644 index 660f6ce03b44..000000000000 --- a/arch/arm64/kernel/perf_trace_counters.h +++ /dev/null @@ -1,110 +0,0 @@ -/* Copyright (c) 2013-2014,2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only 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. - */ - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM perf_trace_counters - -#if !defined(_PERF_TRACE_COUNTERS_H_) || defined(TRACE_HEADER_MULTI_READ) -#define _PERF_TRACE_COUNTERS_H_ - -/* Ctr index for PMCNTENSET/CLR */ -#define CC 0x80000000 -#define C0 0x1 -#define C1 0x2 -#define C2 0x4 -#define C3 0x8 -#define C4 0x10 -#define C5 0x20 -#define C_ALL (CC | C0 | C1 | C2 | C3 | C4 | C5) -#define NUM_L1_CTRS 6 - -#include -#include -#include - -DECLARE_PER_CPU(u32, cntenset_val); -DECLARE_PER_CPU(u32, previous_ccnt); -DECLARE_PER_CPU(u32[NUM_L1_CTRS], previous_l1_cnts); -TRACE_EVENT(sched_switch_with_ctrs, - - TP_PROTO(pid_t prev, pid_t next), - - TP_ARGS(prev, next), - - TP_STRUCT__entry( - __field(pid_t, old_pid) - __field(pid_t, new_pid) - __field(u32, cctr) - __field(u32, ctr0) - __field(u32, ctr1) - __field(u32, ctr2) - __field(u32, ctr3) - __field(u32, ctr4) - __field(u32, ctr5) - ), - - TP_fast_assign( - u32 cpu = smp_processor_id(); - u32 i; - u32 cnten_val; - u32 total_ccnt = 0; - u32 total_cnt = 0; - u32 delta_l1_cnts[NUM_L1_CTRS]; - - __entry->old_pid = prev; - __entry->new_pid = next; - - cnten_val = per_cpu(cntenset_val, cpu); - - if (cnten_val & CC) { - /* Read value */ - total_ccnt = read_sysreg(pmccntr_el0); - __entry->cctr = total_ccnt - - per_cpu(previous_ccnt, cpu); - per_cpu(previous_ccnt, cpu) = total_ccnt; - } - for (i = 0; i < NUM_L1_CTRS; i++) { - if (cnten_val & (1 << i)) { - /* Select */ - write_sysreg(i, pmselr_el0); - isb(); - /* Read value */ - total_cnt = read_sysreg(pmxevcntr_el0); - delta_l1_cnts[i] = total_cnt - - per_cpu(previous_l1_cnts[i], cpu); - per_cpu(previous_l1_cnts[i], cpu) = - total_cnt; - } else - delta_l1_cnts[i] = 0; - } - - __entry->ctr0 = delta_l1_cnts[0]; - __entry->ctr1 = delta_l1_cnts[1]; - __entry->ctr2 = delta_l1_cnts[2]; - __entry->ctr3 = delta_l1_cnts[3]; - __entry->ctr4 = delta_l1_cnts[4]; - __entry->ctr5 = delta_l1_cnts[5]; - ), - - TP_printk("prev_pid=%d, next_pid=%d, CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, CTR4: %u, CTR5: %u", - __entry->old_pid, __entry->new_pid, - __entry->cctr, - __entry->ctr0, __entry->ctr1, - __entry->ctr2, __entry->ctr3, - __entry->ctr4, __entry->ctr5) -); - -#endif -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH ../../arch/arm64/kernel -#define TRACE_INCLUDE_FILE perf_trace_counters -#include diff --git a/arch/arm64/kernel/perf_trace_user.c b/arch/arm64/kernel/perf_trace_user.c deleted file mode 100644 index 0e83f82933ec..000000000000 --- a/arch/arm64/kernel/perf_trace_user.c +++ /dev/null @@ -1,96 +0,0 @@ -/* Copyright (c) 2014,2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only 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. - */ -#include -#include -#include -#include -#include -#include -#include -#include - -#define CREATE_TRACE_POINTS -#include "perf_trace_user.h" - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM perf_trace_counters - -#define TRACE_USER_MAX_BUF_SIZE 100 - -static ssize_t perf_trace_write(struct file *file, - const char __user *user_string_in, - size_t len, loff_t *ppos) -{ - u32 cnten_val; - int rc; - char buf[TRACE_USER_MAX_BUF_SIZE + 1]; - ssize_t length; - - if (len == 0) - return 0; - - length = len > TRACE_USER_MAX_BUF_SIZE ? TRACE_USER_MAX_BUF_SIZE : len; - - rc = copy_from_user(buf, user_string_in, length); - if (rc) { - pr_err("%s copy_from_user failed, rc=%d\n", __func__, rc); - return -EFAULT; - } - - /* Remove any trailing newline and make sure string is terminated */ - if (buf[length - 1] == '\n') - buf[length - 1] = '\0'; - else - buf[length] = '\0'; - - /* - * Disable preemption to ensure that all the performance counter - * accesses happen on the same cpu - */ - preempt_disable(); - /* stop counters, call the trace function, restart them */ - - cnten_val = read_sysreg(pmcntenset_el0); - /* Disable all the counters that were enabled */ - write_sysreg(cnten_val, pmcntenclr_el0); - - trace_perf_trace_user(buf, cnten_val); - - /* Enable all the counters that were disabled */ - write_sysreg(cnten_val, pmcntenset_el0); - preempt_enable(); - - return length; -} - -static const struct file_operations perf_trace_fops = { - .write = perf_trace_write -}; - -static int __init init_perf_trace(void) -{ - struct dentry *dir; - struct dentry *file; - unsigned int value = 1; - - dir = debugfs_create_dir("msm_perf", NULL); - if (!dir) - return -ENOMEM; - file = debugfs_create_file("trace_marker", 0220, dir, - &value, &perf_trace_fops); - if (!file) - return -ENOMEM; - - return 0; -} - -late_initcall(init_perf_trace); diff --git a/arch/arm64/kernel/perf_trace_user.h b/arch/arm64/kernel/perf_trace_user.h deleted file mode 100644 index 4ef10e09d226..000000000000 --- a/arch/arm64/kernel/perf_trace_user.h +++ /dev/null @@ -1,84 +0,0 @@ -/* Copyright (c) 2014,2017 The Linux Foundation. All rights reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 and - * only 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. - */ -#if !defined(_PERF_TRACE_USER_H_) || defined(TRACE_HEADER_MULTI_READ) -#define _PERF_TRACE_USER_H_ - -#undef TRACE_SYSTEM -#define TRACE_SYSTEM perf_trace_counters - -#include - -#define CNTENSET_CC 0x80000000 -#define NUM_L1_CTRS 6 - -TRACE_EVENT(perf_trace_user, - TP_PROTO(char *string, u32 cnten_val), - TP_ARGS(string, cnten_val), - - TP_STRUCT__entry( - __field(u32, cctr) - __field(u32, ctr0) - __field(u32, ctr1) - __field(u32, ctr2) - __field(u32, ctr3) - __field(u32, ctr4) - __field(u32, ctr5) - __string(user_string, string) - ), - - TP_fast_assign( - u32 cnt; - u32 l1_cnts[NUM_L1_CTRS]; - int i; - - if (cnten_val & CNTENSET_CC) { - /* Read value */ - cnt = read_sysreg(pmccntr_el0); - __entry->cctr = cnt; - } else - __entry->cctr = 0; - for (i = 0; i < NUM_L1_CTRS; i++) { - if (cnten_val & (1 << i)) { - /* Select */ - write_sysreg(i, pmselr_el0); - isb(); - /* Read value */ - cnt = read_sysreg(pmxevcntr_el0); - l1_cnts[i] = cnt; - } else { - l1_cnts[i] = 0; - } - } - - __entry->ctr0 = l1_cnts[0]; - __entry->ctr1 = l1_cnts[1]; - __entry->ctr2 = l1_cnts[2]; - __entry->ctr3 = l1_cnts[3]; - __entry->ctr4 = l1_cnts[4]; - __entry->ctr5 = l1_cnts[5]; - __assign_str(user_string, string); - ), - - TP_printk("CCNTR: %u, CTR0: %u, CTR1: %u, CTR2: %u, CTR3: %u, CTR4: %u, CTR5: %u, MSG=%s", - __entry->cctr, - __entry->ctr0, __entry->ctr1, - __entry->ctr2, __entry->ctr3, - __entry->ctr4, __entry->ctr5, - __get_str(user_string) - ) -); - -#endif -#undef TRACE_INCLUDE_PATH -#define TRACE_INCLUDE_PATH ../../arch/arm64/kernel -#define TRACE_INCLUDE_FILE perf_trace_user -#include diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c index f7a5b92bfcee..18fc5e96d9e1 100644 --- a/arch/arm64/kernel/smp.c +++ b/arch/arm64/kernel/smp.c @@ -831,12 +831,10 @@ void arch_send_call_function_single_ipi(int cpu) smp_cross_call_common(cpumask_of(cpu), IPI_CALL_FUNC); } -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL void arch_send_wakeup_ipi_mask(const struct cpumask *mask) { smp_cross_call_common(mask, IPI_WAKEUP); } -#endif #ifdef CONFIG_IRQ_WORK void arch_irq_work_raise(void) @@ -954,13 +952,8 @@ void handle_IPI(int ipinr, struct pt_regs *regs) break; #endif -#ifdef CONFIG_ARM64_ACPI_PARKING_PROTOCOL case IPI_WAKEUP: - WARN_ONCE(!acpi_parking_protocol_valid(cpu), - "CPU%u: Wake-up IPI outside the ACPI parking protocol\n", - cpu); break; -#endif default: pr_crit("CPU%u: Unknown IPI message 0x%x\n", cpu, ipinr); diff --git a/arch/arm64/lib/copy_template.S b/arch/arm64/lib/copy_template.S index f5b9210f1c83..7d2e550d4282 100644 --- a/arch/arm64/lib/copy_template.S +++ b/arch/arm64/lib/copy_template.S @@ -51,6 +51,7 @@ C_h .req x12 D_l .req x13 D_h .req x14 + prfm pldl1strm, [src, #(1*L1_CACHE_BYTES)] mov dst, dstin cmp count, #16 /*When memory length is less than 16, the accessed are not aligned.*/ @@ -181,6 +182,7 @@ D_h .req x14 ldp1 C_l, C_h, src, #16 stp1 D_l, D_h, dst, #16 ldp1 D_l, D_h, src, #16 + prfm pldl1strm, [src, #(4*L1_CACHE_BYTES)] subs count, count, #64 b.ge 1b stp1 A_l, A_h, dst, #16 diff --git a/arch/arm64/lib/memchr.S b/arch/arm64/lib/memchr.S index 4444c1d25f4b..0f164a4baf52 100644 --- a/arch/arm64/lib/memchr.S +++ b/arch/arm64/lib/memchr.S @@ -30,7 +30,7 @@ * Returns: * x0 - address of first occurrence of 'c' or 0 */ -ENTRY(memchr) +WEAK(memchr) and w1, w1, #0xff 1: subs x2, x2, #1 b.mi 2f diff --git a/arch/arm64/lib/memcmp.S b/arch/arm64/lib/memcmp.S index 2a4e239bd17a..f365a5055c30 100644 --- a/arch/arm64/lib/memcmp.S +++ b/arch/arm64/lib/memcmp.S @@ -1,258 +1,131 @@ /* - * Copyright (C) 2013 ARM Ltd. - * Copyright (C) 2013 Linaro. + * Copyright (c) 2017 ARM Ltd + * All rights reserved. * - * This code is based on glibc cortex strings work originally authored by Linaro - * and re-licensed under GPLv2 for the Linux kernel. The original code can - * be found @ + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the company may not be used to endorse or promote + * products derived from this software without specific prior written + * permission. * - * http://bazaar.launchpad.net/~linaro-toolchain-dev/cortex-strings/trunk/ - * files/head:/src/aarch64/ - * - * 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. + * THIS SOFTWARE IS PROVIDED BY ARM LTD ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL ARM LTD BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* Assumptions: * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . + * ARMv8-a, AArch64, unaligned accesses. */ +/* includes here */ #include #include -/* -* compare memory areas(when two memory areas' offset are different, -* alignment handled by the hardware) -* -* Parameters: -* x0 - const memory area 1 pointer -* x1 - const memory area 2 pointer -* x2 - the maximal compare byte length -* Returns: -* x0 - a compare result, maybe less than, equal to, or greater than ZERO -*/ - /* Parameters and result. */ -src1 .req x0 -src2 .req x1 -limit .req x2 -result .req x0 +#define src1 x0 +#define src2 x1 +#define limit x2 +#define result w0 /* Internal variables. */ -data1 .req x3 -data1w .req w3 -data2 .req x4 -data2w .req w4 -has_nul .req x5 -diff .req x6 -endloop .req x7 -tmp1 .req x8 -tmp2 .req x9 -tmp3 .req x10 -pos .req x11 -limit_wd .req x12 -mask .req x13 - -ENTRY(memcmp) - cbz limit, .Lret0 - eor tmp1, src1, src2 - tst tmp1, #7 - b.ne .Lmisaligned8 - ands tmp1, src1, #7 - b.ne .Lmutual_align - sub limit_wd, limit, #1 /* limit != 0, so no underflow. */ - lsr limit_wd, limit_wd, #3 /* Convert to Dwords. */ - /* - * The input source addresses are at alignment boundary. - * Directly compare eight bytes each time. - */ -.Lloop_aligned: - ldr data1, [src1], #8 - ldr data2, [src2], #8 -.Lstart_realigned: - subs limit_wd, limit_wd, #1 - eor diff, data1, data2 /* Non-zero if differences found. */ - csinv endloop, diff, xzr, cs /* Last Dword or differences. */ - cbz endloop, .Lloop_aligned - - /* Not reached the limit, must have found a diff. */ - tbz limit_wd, #63, .Lnot_limit - - /* Limit % 8 == 0 => the diff is in the last 8 bytes. */ - ands limit, limit, #7 - b.eq .Lnot_limit - /* - * The remained bytes less than 8. It is needed to extract valid data - * from last eight bytes of the intended memory range. - */ - lsl limit, limit, #3 /* bytes-> bits. */ - mov mask, #~0 -CPU_BE( lsr mask, mask, limit ) -CPU_LE( lsl mask, mask, limit ) - bic data1, data1, mask - bic data2, data2, mask - - orr diff, diff, mask - b .Lnot_limit - -.Lmutual_align: - /* - * Sources are mutually aligned, but are not currently at an - * alignment boundary. Round down the addresses and then mask off - * the bytes that precede the start point. - */ - bic src1, src1, #7 - bic src2, src2, #7 - ldr data1, [src1], #8 - ldr data2, [src2], #8 - /* - * We can not add limit with alignment offset(tmp1) here. Since the - * addition probably make the limit overflown. - */ - sub limit_wd, limit, #1/*limit != 0, so no underflow.*/ - and tmp3, limit_wd, #7 - lsr limit_wd, limit_wd, #3 - add tmp3, tmp3, tmp1 - add limit_wd, limit_wd, tmp3, lsr #3 - add limit, limit, tmp1/* Adjust the limit for the extra. */ - - lsl tmp1, tmp1, #3/* Bytes beyond alignment -> bits.*/ - neg tmp1, tmp1/* Bits to alignment -64. */ - mov tmp2, #~0 - /*mask off the non-intended bytes before the start address.*/ -CPU_BE( lsl tmp2, tmp2, tmp1 )/*Big-endian.Early bytes are at MSB*/ - /* Little-endian. Early bytes are at LSB. */ -CPU_LE( lsr tmp2, tmp2, tmp1 ) - - orr data1, data1, tmp2 - orr data2, data2, tmp2 - b .Lstart_realigned - - /*src1 and src2 have different alignment offset.*/ -.Lmisaligned8: - cmp limit, #8 - b.lo .Ltiny8proc /*limit < 8: compare byte by byte*/ - - and tmp1, src1, #7 - neg tmp1, tmp1 - add tmp1, tmp1, #8/*valid length in the first 8 bytes of src1*/ - and tmp2, src2, #7 - neg tmp2, tmp2 - add tmp2, tmp2, #8/*valid length in the first 8 bytes of src2*/ - subs tmp3, tmp1, tmp2 - csel pos, tmp1, tmp2, hi /*Choose the maximum.*/ - - sub limit, limit, pos - /*compare the proceeding bytes in the first 8 byte segment.*/ -.Ltinycmp: - ldrb data1w, [src1], #1 - ldrb data2w, [src2], #1 - subs pos, pos, #1 - ccmp data1w, data2w, #0, ne /* NZCV = 0b0000. */ - b.eq .Ltinycmp - cbnz pos, 1f /*diff occurred before the last byte.*/ +#define data1 x3 +#define data1w w3 +#define data2 x4 +#define data2w w4 +#define tmp1 x5 + +/* Small inputs of less than 8 bytes are handled separately. This allows the + main code to be sped up using unaligned loads since there are now at least + 8 bytes to be compared. If the first 8 bytes are equal, align src1. + This ensures each iteration does at most one unaligned access even if both + src1 and src2 are unaligned, and mutually aligned inputs behave as if + aligned. After the main loop, process the last 8 bytes using unaligned + accesses. */ + +.p2align 6 +WEAK(memcmp) + subs limit, limit, 8 + b.lo .Lless8 + + /* Limit >= 8, so check first 8 bytes using unaligned loads. */ + ldr data1, [src1], 8 + ldr data2, [src2], 8 + and tmp1, src1, 7 + add limit, limit, tmp1 + cmp data1, data2 + bne .Lreturn + + /* Align src1 and adjust src2 with bytes not yet done. */ + sub src1, src1, tmp1 + sub src2, src2, tmp1 + + subs limit, limit, 8 + b.ls .Llast_bytes + + /* Loop performing 8 bytes per iteration using aligned src1. + Limit is pre-decremented by 8 and must be larger than zero. + Exit if <= 8 bytes left to do or if the data is not equal. */ + .p2align 4 +.Lloop8: + ldr data1, [src1], 8 + ldr data2, [src2], 8 + subs limit, limit, 8 + ccmp data1, data2, 0, hi /* NZCV = 0b0000. */ + b.eq .Lloop8 + + cmp data1, data2 + bne .Lreturn + + /* Compare last 1-8 bytes using unaligned access. */ +.Llast_bytes: + ldr data1, [src1, limit] + ldr data2, [src2, limit] + + /* Compare data bytes and set return value to 0, -1 or 1. */ +.Lreturn: +#ifndef __AARCH64EB__ + rev data1, data1 + rev data2, data2 +#endif + cmp data1, data2 +.Lret_eq: + cset result, ne + cneg result, result, lo + ret + + .p2align 4 + /* Compare up to 8 bytes. Limit is [-8..-1]. */ +.Lless8: + adds limit, limit, 4 + b.lo .Lless4 + ldr data1w, [src1], 4 + ldr data2w, [src2], 4 cmp data1w, data2w - b.eq .Lstart_align -1: - sub result, data1, data2 - ret - -.Lstart_align: - lsr limit_wd, limit, #3 - cbz limit_wd, .Lremain8 - - ands xzr, src1, #7 - b.eq .Lrecal_offset - /*process more leading bytes to make src1 aligned...*/ - add src1, src1, tmp3 /*backwards src1 to alignment boundary*/ - add src2, src2, tmp3 - sub limit, limit, tmp3 - lsr limit_wd, limit, #3 - cbz limit_wd, .Lremain8 - /*load 8 bytes from aligned SRC1..*/ - ldr data1, [src1], #8 - ldr data2, [src2], #8 - - subs limit_wd, limit_wd, #1 - eor diff, data1, data2 /*Non-zero if differences found.*/ - csinv endloop, diff, xzr, ne - cbnz endloop, .Lunequal_proc - /*How far is the current SRC2 from the alignment boundary...*/ - and tmp3, tmp3, #7 - -.Lrecal_offset:/*src1 is aligned now..*/ - neg pos, tmp3 -.Lloopcmp_proc: - /* - * Divide the eight bytes into two parts. First,backwards the src2 - * to an alignment boundary,load eight bytes and compare from - * the SRC2 alignment boundary. If all 8 bytes are equal,then start - * the second part's comparison. Otherwise finish the comparison. - * This special handle can garantee all the accesses are in the - * thread/task space in avoid to overrange access. - */ - ldr data1, [src1,pos] - ldr data2, [src2,pos] - eor diff, data1, data2 /* Non-zero if differences found. */ - cbnz diff, .Lnot_limit - - /*The second part process*/ - ldr data1, [src1], #8 - ldr data2, [src2], #8 - eor diff, data1, data2 /* Non-zero if differences found. */ - subs limit_wd, limit_wd, #1 - csinv endloop, diff, xzr, ne/*if limit_wd is 0,will finish the cmp*/ - cbz endloop, .Lloopcmp_proc -.Lunequal_proc: - cbz diff, .Lremain8 - -/* There is difference occurred in the latest comparison. */ -.Lnot_limit: -/* -* For little endian,reverse the low significant equal bits into MSB,then -* following CLZ can find how many equal bits exist. -*/ -CPU_LE( rev diff, diff ) -CPU_LE( rev data1, data1 ) -CPU_LE( rev data2, data2 ) - - /* - * The MS-non-zero bit of DIFF marks either the first bit - * that is different, or the end of the significant data. - * Shifting left now will bring the critical information into the - * top bits. - */ - clz pos, diff - lsl data1, data1, pos - lsl data2, data2, pos - /* - * We need to zero-extend (char is unsigned) the value and then - * perform a signed subtraction. - */ - lsr data1, data1, #56 - sub result, data1, data2, lsr #56 - ret - -.Lremain8: - /* Limit % 8 == 0 =>. all data are equal.*/ - ands limit, limit, #7 - b.eq .Lret0 - -.Ltiny8proc: - ldrb data1w, [src1], #1 - ldrb data2w, [src2], #1 - subs limit, limit, #1 - - ccmp data1w, data2w, #0, ne /* NZCV = 0b0000. */ - b.eq .Ltiny8proc - sub result, data1, data2 - ret -.Lret0: - mov result, #0 + b.ne .Lreturn + sub limit, limit, 4 +.Lless4: + adds limit, limit, 4 + beq .Lret_eq +.Lbyte_loop: + ldrb data1w, [src1], 1 + ldrb data2w, [src2], 1 + subs limit, limit, 1 + ccmp data1w, data2w, 0, ne /* NZCV = 0b0000. */ + b.eq .Lbyte_loop + sub result, data1w, data2w ret ENDPIPROC(memcmp) diff --git a/arch/arm64/lib/memmove.S b/arch/arm64/lib/memmove.S index a5a4459013b1..f5ac945d2a65 100644 --- a/arch/arm64/lib/memmove.S +++ b/arch/arm64/lib/memmove.S @@ -60,6 +60,7 @@ D_h .req x14 .weak memmove ENTRY(__memmove) ENTRY(memmove) + prfm pldl1strm, [src, #L1_CACHE_BYTES] cmp dstin, src b.lo __memcpy add tmp1, src, count @@ -186,6 +187,7 @@ ENTRY(memmove) ldp C_l, C_h, [src, #-48] stp D_l, D_h, [dst, #-64]! ldp D_l, D_h, [src, #-64]! + prfm pldl1strm, [src, #(4*L1_CACHE_BYTES)] subs count, count, #64 b.ge 1b stp A_l, A_h, [dst, #-16] diff --git a/arch/arm64/lib/strchr.S b/arch/arm64/lib/strchr.S index dae0cf5591f9..7c83091d1bcd 100644 --- a/arch/arm64/lib/strchr.S +++ b/arch/arm64/lib/strchr.S @@ -29,7 +29,7 @@ * Returns: * x0 - address of first occurrence of 'c' or 0 */ -ENTRY(strchr) +WEAK(strchr) and w1, w1, #0xff 1: ldrb w2, [x0], #1 cmp w2, w1 diff --git a/arch/arm64/lib/strcmp.S b/arch/arm64/lib/strcmp.S index 471fe61760ef..7d5d15398bfb 100644 --- a/arch/arm64/lib/strcmp.S +++ b/arch/arm64/lib/strcmp.S @@ -60,7 +60,7 @@ tmp3 .req x9 zeroones .req x10 pos .req x11 -ENTRY(strcmp) +WEAK(strcmp) eor tmp1, src1, src2 mov zeroones, #REP8_01 tst tmp1, #7 diff --git a/arch/arm64/lib/strlen.S b/arch/arm64/lib/strlen.S index 55ccc8e24c08..8e0b14205dcb 100644 --- a/arch/arm64/lib/strlen.S +++ b/arch/arm64/lib/strlen.S @@ -56,7 +56,7 @@ pos .req x12 #define REP8_7f 0x7f7f7f7f7f7f7f7f #define REP8_80 0x8080808080808080 -ENTRY(strlen) +WEAK(strlen) mov zeroones, #REP8_01 bic src, srcin, #15 ands tmp1, srcin, #15 diff --git a/arch/arm64/lib/strncmp.S b/arch/arm64/lib/strncmp.S index e267044761c6..66bd145935d9 100644 --- a/arch/arm64/lib/strncmp.S +++ b/arch/arm64/lib/strncmp.S @@ -64,7 +64,7 @@ limit_wd .req x13 mask .req x14 endloop .req x15 -ENTRY(strncmp) +WEAK(strncmp) cbz limit, .Lret0 eor tmp1, src1, src2 mov zeroones, #REP8_01 diff --git a/arch/arm64/lib/strnlen.S b/arch/arm64/lib/strnlen.S index eae38da6e0bb..355be04441fe 100644 --- a/arch/arm64/lib/strnlen.S +++ b/arch/arm64/lib/strnlen.S @@ -59,7 +59,7 @@ limit_wd .req x14 #define REP8_7f 0x7f7f7f7f7f7f7f7f #define REP8_80 0x8080808080808080 -ENTRY(strnlen) +WEAK(strnlen) cbz limit, .Lhit_limit mov zeroones, #REP8_01 bic src, srcin, #15 diff --git a/arch/arm64/lib/strrchr.S b/arch/arm64/lib/strrchr.S index 61eabd9a289a..f3b9f8e2917c 100644 --- a/arch/arm64/lib/strrchr.S +++ b/arch/arm64/lib/strrchr.S @@ -29,7 +29,7 @@ * Returns: * x0 - address of last occurrence of 'c' or 0 */ -ENTRY(strrchr) +WEAK(strrchr) mov x3, #0 and w1, w1, #0xff 1: ldrb w2, [x0], #1 diff --git a/drivers/android/binder.c b/drivers/android/binder.c index 64824dc8fc22..08b8795b3974 100644 --- a/drivers/android/binder.c +++ b/drivers/android/binder.c @@ -136,8 +136,7 @@ enum { BINDER_DEBUG_PRIORITY_CAP = 1U << 13, BINDER_DEBUG_SPINLOCKS = 1U << 14, }; -static uint32_t binder_debug_mask = BINDER_DEBUG_USER_ERROR | - BINDER_DEBUG_FAILED_TRANSACTION | BINDER_DEBUG_DEAD_TRANSACTION; +static uint32_t binder_debug_mask = 0; module_param_named(debug_mask, binder_debug_mask, uint, 0644); static char *binder_devices_param = CONFIG_ANDROID_BINDER_DEVICES; diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 4c57bff0fe95..49b4191a74fd 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -1895,8 +1895,10 @@ unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy, target_freq = clamp_val(target_freq, policy->min, policy->max); ret = cpufreq_driver->fast_switch(policy, target_freq); - if (ret) + if (ret) { cpufreq_times_record_transition(policy, ret); + cpufreq_stats_record_transition(policy, ret); + } return ret; } diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index e75880eb037d..6e38b2463a80 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -14,15 +14,13 @@ #include #include -static DEFINE_SPINLOCK(cpufreq_stats_lock); - struct cpufreq_stats { unsigned int total_trans; - unsigned long long last_time; + atomic64_t last_time; unsigned int max_state; unsigned int state_num; unsigned int last_index; - u64 *time_in_state; + atomic64_t *time_in_state; unsigned int *freq_table; unsigned int *trans_table; }; @@ -30,11 +28,10 @@ struct cpufreq_stats { static int cpufreq_stats_update(struct cpufreq_stats *stats) { unsigned long long cur_time = get_jiffies_64(); + unsigned long long time = cur_time; - spin_lock(&cpufreq_stats_lock); - stats->time_in_state[stats->last_index] += cur_time - stats->last_time; - stats->last_time = cur_time; - spin_unlock(&cpufreq_stats_lock); + time = atomic64_xchg(&stats->last_time, time); + atomic64_add(cur_time - time, &stats->time_in_state[stats->last_index]); return 0; } @@ -42,9 +39,9 @@ static void cpufreq_stats_clear_table(struct cpufreq_stats *stats) { unsigned int count = stats->max_state; - memset(stats->time_in_state, 0, count * sizeof(u64)); + memset(stats->time_in_state, 0, count * sizeof(atomic64_t)); memset(stats->trans_table, 0, count * count * sizeof(int)); - stats->last_time = get_jiffies_64(); + atomic64_set(&stats->last_time, get_jiffies_64()); stats->total_trans = 0; } @@ -59,14 +56,12 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) ssize_t len = 0; int i; - if (policy->fast_switch_enabled) - return 0; - cpufreq_stats_update(stats); for (i = 0; i < stats->state_num; i++) { len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i], (unsigned long long) - jiffies_64_to_clock_t(stats->time_in_state[i])); + jiffies_64_to_clock_t(atomic64_read( + &stats->time_in_state[i]))); } return len; } @@ -85,9 +80,6 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) ssize_t len = 0; int i, j; - if (policy->fast_switch_enabled) - return 0; - len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n"); len += snprintf(buf + len, PAGE_SIZE - len, " : "); for (i = 0; i < stats->state_num; i++) { @@ -184,7 +176,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) if (!stats) return; - alloc_size = count * sizeof(int) + count * sizeof(u64); + alloc_size = count * sizeof(int) + count * sizeof(atomic64_t); alloc_size += count * count * sizeof(int); @@ -205,7 +197,7 @@ void cpufreq_stats_create_table(struct cpufreq_policy *policy) stats->freq_table[i++] = pos->frequency; stats->state_num = i; - stats->last_time = get_jiffies_64(); + atomic64_set(&stats->last_time, get_jiffies_64()); stats->last_index = freq_table_get_index(stats, policy->cur); policy->stats = stats; diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig index 7e48eb5bf0a7..cdf3e45fa942 100644 --- a/drivers/cpuidle/Kconfig +++ b/drivers/cpuidle/Kconfig @@ -3,8 +3,6 @@ menu "CPU Idle" config CPU_IDLE bool "CPU idle PM support" default y if ACPI || PPC_PSERIES - select CPU_IDLE_GOV_LADDER if (!NO_HZ && !NO_HZ_IDLE) - select CPU_IDLE_GOV_MENU if (NO_HZ || NO_HZ_IDLE) help CPU idle is a generic framework for supporting software-controlled idle processor power management. It includes modular cross-platform diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 235d21cda429..716755efb681 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -37,6 +37,27 @@ static int enabled_devices; static int off __read_mostly; static int initialized __read_mostly; +#ifdef CONFIG_SMP +static atomic_t idled = ATOMIC_INIT(0); + +#if NR_CPUS > 32 +#error idled CPU mask not big enough for NR_CPUS +#endif + +static void cpuidle_set_idle_cpu(unsigned int cpu) +{ + atomic_or(BIT(cpu), &idled); +} + +static void cpuidle_clear_idle_cpu(unsigned int cpu) +{ + atomic_andnot(BIT(cpu), &idled); +} +#else +static inline void cpuidle_set_idle_cpu(unsigned int cpu) { } +static inline void cpuidle_clear_idle_cpu(unsigned int cpu) { } +#endif + int cpuidle_disabled(void) { return off; @@ -219,7 +240,9 @@ int cpuidle_enter_state(struct cpuidle_device *dev, struct cpuidle_driver *drv, time_start = ns_to_ktime(local_clock()); stop_critical_timings(); + cpuidle_set_idle_cpu(dev->cpu); entered_state = target_state->enter(dev, drv, index); + cpuidle_clear_idle_cpu(dev->cpu); start_critical_timings(); sched_clock_idle_wakeup_event(); @@ -643,22 +666,12 @@ EXPORT_SYMBOL_GPL(cpuidle_register); static void wake_up_idle_cpus(void *v) { - int cpu; - struct cpumask cpus; + unsigned long cpus = atomic_read(&idled) & *cpumask_bits(to_cpumask(v)); - preempt_disable(); - if (v) { - cpumask_andnot(&cpus, v, cpu_isolated_mask); - cpumask_and(&cpus, &cpus, cpu_online_mask); - } else - cpumask_andnot(&cpus, cpu_online_mask, cpu_isolated_mask); - - for_each_cpu(cpu, &cpus) { - if (cpu == smp_processor_id()) - continue; - wake_up_if_idle(cpu); - } - preempt_enable(); + /* Use READ_ONCE to get the isolated mask outside cpu_add_remove_lock */ + cpus &= ~READ_ONCE(*cpumask_bits(cpu_isolated_mask)); + if (cpus) + arch_send_wakeup_ipi_mask(to_cpumask(&cpus)); } /* diff --git a/drivers/cpuidle/lpm-levels.c b/drivers/cpuidle/lpm-levels.c index ac2c6f7ea8d0..f4b45e1edca9 100644 --- a/drivers/cpuidle/lpm-levels.c +++ b/drivers/cpuidle/lpm-levels.c @@ -686,7 +686,7 @@ static int cpu_power_select(struct cpuidle_device *dev, min_residency = pwr_params->min_residency; max_residency = pwr_params->max_residency; - if (latency_us < lvl_latency_us) + if (latency_us <= lvl_latency_us) break; if (next_event_us) { @@ -1026,7 +1026,7 @@ static int cluster_select(struct lpm_cluster *cluster, bool from_idle, &level->num_cpu_votes)) continue; - if (from_idle && latency_us < pwr_params->exit_latency) + if (from_idle && latency_us <= pwr_params->exit_latency) break; if (sleep_us < (pwr_params->exit_latency + @@ -1107,7 +1107,7 @@ static int cluster_configure(struct lpm_cluster *cluster, int idx, * LPMs(XO and Vmin). */ if (!from_idle) - clock_debug_print_enabled(true); + clock_debug_print_enabled(false); cpu = get_next_online_cpu(from_idle); cpumask_copy(&cpumask, cpumask_of(cpu)); diff --git a/drivers/crypto/msm/qce50.c b/drivers/crypto/msm/qce50.c index 570b5802808f..09c591816818 100644 --- a/drivers/crypto/msm/qce50.c +++ b/drivers/crypto/msm/qce50.c @@ -4676,7 +4676,7 @@ static int select_mode(struct qce_device *pce_dev, pce_dev->intr_cadence = 0; atomic_set(&pce_dev->bunch_cmd_seq, 0); atomic_set(&pce_dev->last_intr_seq, 0); - pce_dev->cadence_flag = ~pce_dev->cadence_flag; + pce_dev->cadence_flag = !pce_dev->cadence_flag; } } diff --git a/drivers/dma/dmaengine.c b/drivers/dma/dmaengine.c index b451354735d3..245b6159dea4 100644 --- a/drivers/dma/dmaengine.c +++ b/drivers/dma/dmaengine.c @@ -1085,6 +1085,9 @@ int dma_async_device_register(struct dma_device *device) dma_channel_rebalance(); mutex_unlock(&dma_list_mutex); + if (!chancnt) + kfree(idr_ref); + return 0; err_out: diff --git a/drivers/gpu/drm/drm_mipi_dsi.c b/drivers/gpu/drm/drm_mipi_dsi.c index 0746ac89fcc5..d72ba5dd71b0 100644 --- a/drivers/gpu/drm/drm_mipi_dsi.c +++ b/drivers/gpu/drm/drm_mipi_dsi.c @@ -1044,6 +1044,20 @@ int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline) } EXPORT_SYMBOL(mipi_dsi_dcs_set_tear_scanline); +int mipi_dsi_dcs_set_display_brightness_ss(struct mipi_dsi_device *dsi, + u16 brightness) +{ + u8 payload[2] = { brightness >> 8, brightness & 0xff }; + ssize_t err; + + err = mipi_dsi_dcs_write(dsi, MIPI_DCS_SET_DISPLAY_BRIGHTNESS, + payload, sizeof(payload)); + if (err < 0) + return err; + + return 0; +} + /** * mipi_dsi_dcs_set_display_brightness() - sets the brightness value of the * display diff --git a/drivers/gpu/drm/msm/Kconfig b/drivers/gpu/drm/msm/Kconfig index 5e1c40a8ac34..bf5cbf48a868 100644 --- a/drivers/gpu/drm/msm/Kconfig +++ b/drivers/gpu/drm/msm/Kconfig @@ -198,3 +198,7 @@ config DRM_SDE_RSC avoids the display core power collapse. A client can also register for display core power collapse events on rsc. +config FENCE_DEBUG + bool "Print fence name to userspace" + depends on DRM_MSM + default n diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h index 904d21507d70..7902ecad8232 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_defs.h @@ -288,6 +288,10 @@ enum dsi_cmd_set_type { DSI_CMD_SET_POST_TIMING_SWITCH, DSI_CMD_SET_QSYNC_ON, DSI_CMD_SET_QSYNC_OFF, + DSI_CMD_SET_DOZE_HBM, + DSI_CMD_SET_DOZE_LBM, + DSI_CMD_SET_DISP_HBM_FOD_ON, + DSI_CMD_SET_DISP_HBM_FOD_OFF, DSI_CMD_SET_MAX }; diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c index f1f306ec2b93..74b966a087b4 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_display.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_display.c @@ -19,6 +19,8 @@ #include #include +#include + #include "msm_drv.h" #include "sde_connector.h" #include "msm_mmu.h" @@ -1074,6 +1076,8 @@ int dsi_display_set_power(struct drm_connector *connector, int power_mode, void *disp) { struct dsi_display *display = disp; + struct msm_drm_notifier notify_data; + int event = power_mode; int rc = 0; if (!display || !display->panel) { @@ -1081,17 +1085,26 @@ int dsi_display_set_power(struct drm_connector *connector, return -EINVAL; } + notify_data.data = &event; + switch (power_mode) { case SDE_MODE_DPMS_LP1: + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, ¬ify_data); rc = dsi_panel_set_lp1(display->panel); + msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK, ¬ify_data); break; case SDE_MODE_DPMS_LP2: + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, ¬ify_data); rc = dsi_panel_set_lp2(display->panel); + msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK, ¬ify_data); break; case SDE_MODE_DPMS_ON: if (display->panel->power_mode == SDE_MODE_DPMS_LP1 || - display->panel->power_mode == SDE_MODE_DPMS_LP2) + display->panel->power_mode == SDE_MODE_DPMS_LP2) { + msm_drm_notifier_call_chain(MSM_DRM_EARLY_EVENT_BLANK, ¬ify_data); rc = dsi_panel_set_nolp(display->panel); + msm_drm_notifier_call_chain(MSM_DRM_EVENT_BLANK, ¬ify_data); + } break; case SDE_MODE_DPMS_OFF: default: @@ -4925,11 +4938,225 @@ static int dsi_display_validate_split_link(struct dsi_display *display) return rc; } +static ssize_t sysfs_doze_status_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dsi_display *display; + struct dsi_panel *panel; + int rc = 0; + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + panel = display->panel; + + mutex_lock(&panel->panel_lock); + rc = snprintf(buf, PAGE_SIZE, "%d\n", panel->doze_enabled); + mutex_unlock(&panel->panel_lock); + + return rc; +} + +static ssize_t sysfs_doze_status_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dsi_display *display; + struct dsi_panel *panel; + int rc = 0; + int status; + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &status); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return rc; + } + + panel = display->panel; + + mutex_lock(&panel->panel_lock); + dsi_panel_set_doze_status(panel, !!status); + mutex_unlock(&panel->panel_lock); + + return count; +} + +static ssize_t sysfs_doze_mode_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dsi_display *display; + struct dsi_panel *panel; + int rc = 0; + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + panel = display->panel; + + mutex_lock(&panel->panel_lock); + rc = snprintf(buf, PAGE_SIZE, "%d\n", panel->doze_mode); + mutex_unlock(&panel->panel_lock); + + return rc; +} + +static ssize_t sysfs_doze_mode_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dsi_display *display; + struct dsi_panel *panel; + int rc = 0; + int mode; + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &mode); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return rc; + } + + if (mode < DSI_DOZE_LPM || mode > DSI_DOZE_HBM) { + pr_err("%s: invalid value for doze mode\n", __func__); + return -EINVAL; + } + + panel = display->panel; + + mutex_lock(&panel->panel_lock); + dsi_panel_set_doze_mode(panel, (enum dsi_doze_mode_type) mode); + mutex_unlock(&panel->panel_lock); + + return count; +} + +static ssize_t sysfs_fod_hbm_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dsi_display *display; + struct dsi_panel *panel; + int rc = 0; + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + panel = display->panel; + + mutex_lock(&panel->panel_lock); + rc = snprintf(buf, PAGE_SIZE, "%d\n", panel->fod_hbm_enabled); + mutex_unlock(&panel->panel_lock); + + return rc; +} + +static ssize_t sysfs_fod_hbm_write(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) +{ + struct dsi_display *display; + struct dsi_panel *panel; + int status; + int rc = 0; + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + rc = kstrtoint(buf, 10, &status); + if (rc) { + pr_err("%s: kstrtoint failed. rc=%d\n", __func__, rc); + return rc; + } + + panel = display->panel; + + mutex_lock(&panel->panel_lock); + dsi_panel_set_fod_hbm_status(panel, !!status); + mutex_unlock(&panel->panel_lock); + + return count; +} + +static ssize_t sysfs_backlight_level_read(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct dsi_display *display; + struct dsi_panel *panel; + u32 bl_level; + int rc = 0; + + display = dev_get_drvdata(dev); + if (!display) { + pr_err("Invalid display\n"); + return -EINVAL; + } + + panel = display->panel; + + mutex_lock(&panel->panel_lock); + bl_level = dsi_panel_get_backlight(panel); + mutex_unlock(&panel->panel_lock); + + rc = snprintf(buf, PAGE_SIZE, "%d\n", bl_level); + + return rc; +} + +static DEVICE_ATTR(doze_status, 0644, + sysfs_doze_status_read, + sysfs_doze_status_write); + +static DEVICE_ATTR(doze_mode, 0644, + sysfs_doze_mode_read, + sysfs_doze_mode_write); + +static DEVICE_ATTR(fod_hbm, 0644, + sysfs_fod_hbm_read, + sysfs_fod_hbm_write); + +static DEVICE_ATTR(backlight_level, 0444, + sysfs_backlight_level_read, + NULL); + +static struct attribute *display_fs_attrs[] = { + &dev_attr_doze_status.attr, + &dev_attr_doze_mode.attr, + &dev_attr_fod_hbm.attr, + &dev_attr_backlight_level.attr, + NULL, +}; +static struct attribute_group display_fs_attrs_group = { + .attrs = display_fs_attrs, +}; + static int dsi_display_sysfs_init(struct dsi_display *display) { int rc = 0; struct device *dev = &display->pdev->dev; + rc = sysfs_create_group(&dev->kobj, &display_fs_attrs_group); + if (rc) + pr_err("failed to create display device attributes"); + if (display->panel->panel_mode == DSI_OP_CMD_MODE) rc = sysfs_create_group(&dev->kobj, &dynamic_dsi_clock_fs_attrs_group); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c index 20cdc7289118..d65f38a6797d 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.c @@ -447,6 +447,10 @@ static int dsi_panel_power_on(struct dsi_panel *panel) goto error_disable_vregs; } + /* If LP11_INIT is set, skip panel reset here*/ + if (panel->lp11_init) + goto exit; + rc = dsi_panel_reset(panel); if (rc) { pr_err("[%s] failed to reset panel, rc=%d\n", panel->name, rc); @@ -620,7 +624,11 @@ static int dsi_panel_update_backlight(struct dsi_panel *panel, dsi = &panel->mipi_device; - rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl); + if (panel->bl_config.dcs_type_ss) + rc = mipi_dsi_dcs_set_display_brightness_ss(dsi, bl_lvl); + else + rc = mipi_dsi_dcs_set_display_brightness(dsi, bl_lvl); + if (rc < 0) pr_err("failed to update dcs backlight:%d\n", bl_lvl); @@ -678,6 +686,82 @@ static int dsi_panel_update_pwm_backlight(struct dsi_panel *panel, return rc; } +int dsi_panel_update_doze(struct dsi_panel *panel) { + int rc = 0; + + if (panel->fod_hbm_enabled) + return 0; + + if (panel->doze_enabled && panel->doze_mode == DSI_DOZE_HBM) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_DOZE_HBM); + if (rc) + pr_err("[%s] failed to send DSI_CMD_SET_DOZE_HBM cmd, rc=%d\n", + panel->name, rc); + } else if (panel->doze_enabled && panel->doze_mode == DSI_DOZE_LPM) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_DOZE_LBM); + if (rc) + pr_err("[%s] failed to send DSI_CMD_SET_DOZE_LBM cmd, rc=%d\n", + panel->name, rc); + } else if (!panel->doze_enabled) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_NOLP); + if (rc) + pr_err("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n", + panel->name, rc); + } + + return rc; +} + +int dsi_panel_set_doze_status(struct dsi_panel *panel, bool status) { + if (panel->doze_enabled == status) + return 0; + + panel->doze_enabled = status; + + return dsi_panel_update_doze(panel); +} + +int dsi_panel_set_doze_mode(struct dsi_panel *panel, enum dsi_doze_mode_type mode) { + if (panel->doze_mode == mode) + return 0; + + panel->doze_mode = mode; + + if (!panel->doze_enabled) + return 0; + + return dsi_panel_update_doze(panel); +} + +int dsi_panel_update_fod_hbm(struct dsi_panel *panel) { + int rc = 0; + + if (panel->fod_hbm_enabled) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_DISP_HBM_FOD_ON); + if (rc) + pr_err("[%s] failed to send DSI_CMD_SET_DISP_HBM_FOD_ON cmd, rc=%d\n", + panel->name, rc); + } else if (!panel->fod_hbm_enabled && panel->doze_enabled) { + dsi_panel_update_doze(panel); + } else if (!panel->fod_hbm_enabled) { + rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_DISP_HBM_FOD_OFF); + if (rc) + pr_err("[%s] failed to send DSI_CMD_SET_DISP_HBM_FOD_OFF cmd, rc=%d\n", + panel->name, rc); + } + + return rc; +} + +int dsi_panel_set_fod_hbm_status(struct dsi_panel *panel, bool status) { + if (panel->fod_hbm_enabled == status) + return 0; + + panel->fod_hbm_enabled = status; + + return dsi_panel_update_fod_hbm(panel); +} + int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl) { int rc = 0; @@ -707,6 +791,20 @@ int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl) return rc; } +u32 dsi_panel_get_backlight(struct dsi_panel *panel) +{ + u32 bl_level; + + if (panel->doze_enabled && panel->doze_mode == DSI_DOZE_HBM) + bl_level = panel->bl_config.bl_doze_hbm; + else if (panel->doze_enabled && panel->doze_mode == DSI_DOZE_LPM) + bl_level = panel->bl_config.bl_doze_lpm; + else if (!panel->doze_enabled) + bl_level = panel->bl_config.bl_level; + + return bl_level; +} + static u32 dsi_panel_get_brightness(struct dsi_backlight_config *bl) { u32 cur_bl_level; @@ -1709,6 +1807,10 @@ const char *cmd_set_prop_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-post-mode-switch-on-command", "qcom,mdss-dsi-qsync-on-commands", "qcom,mdss-dsi-qsync-off-commands", + "qcom,mdss-dsi-doze-hbm-command", + "qcom,mdss-dsi-doze-lbm-command", + "qcom,mdss-dsi-dispparam-hbm-fod-on-command", + "qcom,mdss-dsi-dispparam-hbm-fod-off-command", }; const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { @@ -1735,6 +1837,10 @@ const char *cmd_set_state_map[DSI_CMD_SET_MAX] = { "qcom,mdss-dsi-post-mode-switch-on-command-state", "qcom,mdss-dsi-qsync-on-commands-state", "qcom,mdss-dsi-qsync-off-commands-state", + "qcom,mdss-dsi-doze-hbm-command-state", + "qcom,mdss-dsi-doze-lbm-command-state", + "qcom,mdss-dsi-dispparam-hbm-fod-on-command-state", + "qcom,mdss-dsi-dispparam-hbm-fod-off-command-state", }; static int dsi_panel_get_cmd_pkt_count(const char *data, u32 length, u32 *cnt) @@ -2232,6 +2338,9 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel) panel->bl_config.type = DSI_BACKLIGHT_UNKNOWN; } + panel->bl_config.dcs_type_ss = utils->read_bool(utils->data, + "qcom,mdss-dsi-bl-dcs-type-ss"); + data = utils->get_property(utils->data, "qcom,bl-update-flag", NULL); if (!data) { panel->bl_config.bl_update = BL_UPDATE_NONE; @@ -2284,6 +2393,25 @@ static int dsi_panel_parse_bl_config(struct dsi_panel *panel) panel->bl_config.brightness_default_level = val; } + rc = utils->read_u32(utils->data, + "qcom,disp-doze-lpm-backlight", &val); + if (rc) { + panel->bl_config.bl_doze_lpm = 0; + pr_debug("set doze lpm backlight to 0\n"); + } else { + panel->bl_config.bl_doze_lpm = val; + } + + rc = utils->read_u32(utils->data, + "qcom,disp-doze-hbm-backlight", &val); + if (rc) { + panel->bl_config.bl_doze_hbm = 0; + pr_debug("set doze hbm backlight to 0\n"); + } else { + panel->bl_config.bl_doze_hbm = val; + } + + if (panel->bl_config.type == DSI_BACKLIGHT_PWM) { rc = dsi_panel_parse_bl_pwm_config(panel); if (rc) { @@ -3306,6 +3434,10 @@ struct dsi_panel *dsi_panel_get(struct device *parent, if (rc) pr_debug("failed to parse esd config, rc=%d\n", rc); + panel->doze_mode = DSI_DOZE_LPM; + panel->doze_enabled = false; + panel->fod_hbm_enabled = false; + panel->power_mode = SDE_MODE_DPMS_OFF; drm_panel_init(&panel->drm_panel); mutex_init(&panel->panel_lock); @@ -3686,9 +3818,11 @@ int dsi_panel_pre_prepare(struct dsi_panel *panel) mutex_lock(&panel->panel_lock); +#if 0 /* If LP11_INIT is set, panel will be powered up during prepare() */ if (panel->lp11_init) goto error; +#endif rc = dsi_panel_power_on(panel); if (rc) { @@ -3767,6 +3901,10 @@ int dsi_panel_set_lp1(struct dsi_panel *panel) if (rc) pr_err("[%s] failed to send DSI_CMD_SET_LP1 cmd, rc=%d\n", panel->name, rc); + + rc = dsi_panel_set_doze_status(panel, true); + if (rc) + pr_err("unable to set doze on\n"); exit: mutex_unlock(&panel->panel_lock); return rc; @@ -3789,6 +3927,10 @@ int dsi_panel_set_lp2(struct dsi_panel *panel) if (rc) pr_err("[%s] failed to send DSI_CMD_SET_LP2 cmd, rc=%d\n", panel->name, rc); + + rc = dsi_panel_set_doze_status(panel, true); + if (rc) + pr_err("unable to set doze on\n"); exit: mutex_unlock(&panel->panel_lock); return rc; @@ -3819,6 +3961,10 @@ int dsi_panel_set_nolp(struct dsi_panel *panel) if (rc) pr_err("[%s] failed to send DSI_CMD_SET_NOLP cmd, rc=%d\n", panel->name, rc); + + rc = dsi_panel_set_doze_status(panel, false); + if (rc) + pr_err("unable to set doze on\n"); exit: mutex_unlock(&panel->panel_lock); return rc; @@ -3832,16 +3978,22 @@ int dsi_panel_prepare(struct dsi_panel *panel) pr_err("invalid params\n"); return -EINVAL; } - mutex_lock(&panel->panel_lock); if (panel->lp11_init) { +#if 0 rc = dsi_panel_power_on(panel); if (rc) { pr_err("[%s] panel power on failed, rc=%d\n", panel->name, rc); goto error; } +#endif + rc = dsi_panel_reset(panel); + if (rc) { + pr_err("[%s] failed to reset panel, rc=%d\n", panel->name, rc); + goto error; + } } rc = dsi_panel_tx_cmd_set(panel, DSI_CMD_SET_PRE_ON); @@ -4160,6 +4312,8 @@ int dsi_panel_disable(struct dsi_panel *panel) } panel->panel_initialized = false; panel->power_mode = SDE_MODE_DPMS_OFF; + panel->doze_enabled = false; + panel->fod_hbm_enabled = false; mutex_unlock(&panel->panel_lock); return rc; @@ -4183,6 +4337,14 @@ int dsi_panel_unprepare(struct dsi_panel *panel) goto error; } + if (!panel->lp11_init) { + rc = dsi_panel_power_off(panel); + if (rc) { + pr_err("[%s] panel power_Off failed, rc=%d\n", + panel->name, rc); + goto error; + } + } error: mutex_unlock(&panel->panel_lock); return rc; @@ -4199,11 +4361,13 @@ int dsi_panel_post_unprepare(struct dsi_panel *panel) mutex_lock(&panel->panel_lock); - rc = dsi_panel_power_off(panel); - if (rc) { - pr_err("[%s] panel power_Off failed, rc=%d\n", - panel->name, rc); - goto error; + if (panel->lp11_init) { + rc = dsi_panel_power_off(panel); + if (rc) { + pr_err("[%s] panel power_Off failed, rc=%d\n", + panel->name, rc); + goto error; + } } error: mutex_unlock(&panel->panel_lock); diff --git a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h index f3a1fe8e3b7b..cce25752e381 100644 --- a/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h +++ b/drivers/gpu/drm/msm/dsi-staging/dsi_panel.h @@ -53,6 +53,11 @@ enum dsi_backlight_type { DSI_BACKLIGHT_MAX, }; +enum dsi_doze_mode_type { + DSI_DOZE_LPM = 0, + DSI_DOZE_HBM, +}; + enum bl_update_flag { BL_UPDATE_DELAY_UNTIL_FIRST_FRAME, BL_UPDATE_NONE, @@ -115,8 +120,11 @@ struct dsi_backlight_config { u32 bl_level; u32 bl_scale; u32 bl_scale_ad; + u32 bl_doze_lpm; + u32 bl_doze_hbm; int en_gpio; + bool dcs_type_ss; /* PWM params */ struct pwm_device *pwm_bl; bool pwm_enabled; @@ -212,6 +220,11 @@ struct dsi_panel { bool sync_broadcast_en; int power_mode; enum dsi_panel_physical_type panel_type; + + bool doze_enabled; + enum dsi_doze_mode_type doze_mode; + + bool fod_hbm_enabled; }; static inline bool dsi_panel_ulps_feature_enabled(struct dsi_panel *panel) @@ -298,6 +311,8 @@ int dsi_panel_post_unprepare(struct dsi_panel *panel); int dsi_panel_set_backlight(struct dsi_panel *panel, u32 bl_lvl); +u32 dsi_panel_get_backlight(struct dsi_panel *panel); + int dsi_panel_update_pps(struct dsi_panel *panel); int dsi_panel_send_qsync_on_dcs(struct dsi_panel *panel, @@ -324,4 +339,10 @@ int dsi_panel_parse_esd_reg_read_configs(struct dsi_panel *panel); void dsi_panel_ext_bridge_put(struct dsi_panel *panel); +int dsi_panel_set_doze_status(struct dsi_panel *panel, bool status); + +int dsi_panel_set_doze_mode(struct dsi_panel *panel, enum dsi_doze_mode_type mode); + +int dsi_panel_set_fod_hbm_status(struct dsi_panel *panel, bool status); + #endif /* _DSI_PANEL_H_ */ diff --git a/drivers/gpu/drm/msm/msm_atomic.c b/drivers/gpu/drm/msm/msm_atomic.c index 2d7936278fba..1fb76e553707 100644 --- a/drivers/gpu/drm/msm/msm_atomic.c +++ b/drivers/gpu/drm/msm/msm_atomic.c @@ -73,11 +73,12 @@ EXPORT_SYMBOL(msm_drm_unregister_client); * @v: notifier data, inculde display id and display blank * event(unblank or power down). */ -static int msm_drm_notifier_call_chain(unsigned long val, void *v) +int msm_drm_notifier_call_chain(unsigned long val, void *v) { return blocking_notifier_call_chain(&msm_drm_notifier_list, val, v); } +EXPORT_SYMBOL(msm_drm_notifier_call_chain); /* block until specified crtcs are no longer pending update, and * atomically mark them as pending update diff --git a/drivers/gpu/drm/msm/msm_drv.c b/drivers/gpu/drm/msm/msm_drv.c index 46f4b1fc3e3f..c14556735180 100644 --- a/drivers/gpu/drm/msm/msm_drv.c +++ b/drivers/gpu/drm/msm/msm_drv.c @@ -2131,6 +2131,7 @@ static struct platform_driver msm_platform_driver = { .of_match_table = dt_match, .pm = &msm_pm_ops, .suppress_bind_attrs = true, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.c b/drivers/gpu/drm/msm/sde/sde_encoder.c index 6e75f4de15bf..ac35770dc8cf 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder.c @@ -5823,3 +5823,29 @@ void sde_encoder_recovery_events_handler(struct drm_encoder *encoder, sde_enc = to_sde_encoder_virt(encoder); sde_enc->recovery_events_enabled = enabled; } + +void sde_encoder_trigger_early_wakeup(struct drm_encoder *drm_enc) +{ + struct sde_encoder_virt *sde_enc = NULL; + struct msm_drm_private *priv = NULL; + + priv = drm_enc->dev->dev_private; + sde_enc = to_sde_encoder_virt(drm_enc); + if (!sde_enc->crtc || (sde_enc->crtc->index + >= ARRAY_SIZE(priv->disp_thread))) { + SDE_DEBUG_ENC(sde_enc, + "invalid cached CRTC: %d or crtc index: %d\n", + sde_enc->crtc == NULL, + sde_enc->crtc ? sde_enc->crtc->index : -EINVAL); + return; + } + + SDE_ATRACE_BEGIN("sde_encoder_resource_control"); + if (sde_enc->rc_state == SDE_ENC_RC_STATE_IDLE) { + sde_encoder_resource_control(drm_enc, + SDE_ENC_RC_EVENT_EARLY_WAKEUP); + + } + SDE_ATRACE_END("sde_encoder_resource_control"); + +} diff --git a/drivers/gpu/drm/msm/sde/sde_encoder.h b/drivers/gpu/drm/msm/sde/sde_encoder.h index 95f410201319..9a1692b56934 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder.h @@ -349,4 +349,10 @@ int sde_encoder_in_cont_splash(struct drm_encoder *enc); */ int sde_encoder_get_ctlstart_timeout_state(struct drm_encoder *enc); +/** + * sde_encoder_trigger_early_wakeup - trigger early wake up + * @drm_enc: Pointer to drm encoder structure + */ +void sde_encoder_trigger_early_wakeup(struct drm_encoder *drm_enc); + #endif /* __SDE_ENCODER_H__ */ diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h index 1fe0075d03d3..55b63480d731 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys.h +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys.h @@ -405,6 +405,7 @@ struct sde_encoder_phys_cmd { atomic_t pending_vblank_cnt; wait_queue_head_t pending_vblank_wq; u32 ctl_start_threshold; + struct work_struct ctl_wait_work; }; /** diff --git a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c index c6f5b15c70b4..4b8f7024990e 100644 --- a/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c +++ b/drivers/gpu/drm/msm/sde/sde_encoder_phys_cmd.c @@ -1471,6 +1471,15 @@ static int _sde_encoder_phys_cmd_wait_for_ctl_start( return ret; } +static void sde_encoder_phys_cmd_ctl_start_work(struct work_struct *work) +{ + struct sde_encoder_phys_cmd *cmd_enc = container_of(work, + typeof(*cmd_enc), + ctl_wait_work); + + _sde_encoder_phys_cmd_wait_for_ctl_start(&cmd_enc->base); +} + static int sde_encoder_phys_cmd_wait_for_tx_complete( struct sde_encoder_phys *phys_enc) { @@ -1505,9 +1514,9 @@ static int sde_encoder_phys_cmd_wait_for_commit_done( /* only required for master controller */ if (sde_encoder_phys_cmd_is_master(phys_enc)) - rc = _sde_encoder_phys_cmd_wait_for_ctl_start(phys_enc); + queue_work(system_unbound_wq, &cmd_enc->ctl_wait_work); - if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) && + if (sde_encoder_phys_cmd_is_master(phys_enc) && cmd_enc->autorefresh.cfg.enable) rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc); @@ -1592,6 +1601,9 @@ static void sde_encoder_phys_cmd_prepare_commit( if (!sde_encoder_phys_cmd_is_master(phys_enc)) return; + /* Wait for ctl_start interrupt for the previous commit if needed */ + flush_work(&cmd_enc->ctl_wait_work); + SDE_EVT32(DRMID(phys_enc->parent), phys_enc->intf_idx - INTF_0, cmd_enc->autorefresh.cfg.enable); @@ -1798,6 +1810,7 @@ struct sde_encoder_phys *sde_encoder_phys_cmd_init( init_waitqueue_head(&cmd_enc->pending_vblank_wq); atomic_set(&cmd_enc->autorefresh.kickoff_cnt, 0); init_waitqueue_head(&cmd_enc->autorefresh.kickoff_wq); + INIT_WORK(&cmd_enc->ctl_wait_work, sde_encoder_phys_cmd_ctl_start_work); SDE_DEBUG_CMDENC(cmd_enc, "created\n"); diff --git a/drivers/gpu/drm/msm/sde/sde_fence.c b/drivers/gpu/drm/msm/sde/sde_fence.c index 5b0ef74a8e99..2f4db58d20b9 100644 --- a/drivers/gpu/drm/msm/sde/sde_fence.c +++ b/drivers/gpu/drm/msm/sde/sde_fence.c @@ -91,7 +91,9 @@ uint32_t sde_sync_get_name_prefix(void *fence) struct sde_fence { struct dma_fence base; struct sde_fence_context *ctx; +#ifdef CONFIG_FENCE_DEBUG char name[SDE_FENCE_NAME_SIZE]; +#endif struct list_head fence_list; int fd; }; @@ -116,16 +118,24 @@ static inline struct sde_fence *to_sde_fence(struct dma_fence *fence) static const char *sde_fence_get_driver_name(struct dma_fence *fence) { +#ifdef CONFIG_FENCE_DEBUG struct sde_fence *f = to_sde_fence(fence); return f->name; +#else + return "sde"; +#endif } static const char *sde_fence_get_timeline_name(struct dma_fence *fence) { +#ifdef CONFIG_FENCE_DEBUG struct sde_fence *f = to_sde_fence(fence); return f->ctx->name; +#else + return "timeline"; +#endif } static bool sde_fence_enable_signaling(struct dma_fence *fence) @@ -209,8 +219,10 @@ static int _sde_fence_create_fd(void *fence_ctx, uint32_t val) return -ENOMEM; sde_fence->ctx = fence_ctx; +#ifdef CONFIG_FENCE_DEBUG snprintf(sde_fence->name, SDE_FENCE_NAME_SIZE, "sde_fence:%s:%u", sde_fence->ctx->name, val); +#endif dma_fence_init(&sde_fence->base, &sde_fence_ops, &ctx->lock, ctx->context, val); kref_get(&ctx->kref); @@ -218,8 +230,10 @@ static int _sde_fence_create_fd(void *fence_ctx, uint32_t val) /* create fd */ fd = get_unused_fd_flags(0); if (fd < 0) { +#ifdef CONFIG_FENCE_DEBUG SDE_ERROR("failed to get_unused_fd_flags(), %s\n", sde_fence->name); +#endif dma_fence_put(&sde_fence->base); goto exit; } @@ -229,7 +243,9 @@ static int _sde_fence_create_fd(void *fence_ctx, uint32_t val) if (sync_file == NULL) { put_unused_fd(fd); fd = -EINVAL; +#ifdef CONFIG_FENCE_DEBUG SDE_ERROR("couldn't create fence, %s\n", sde_fence->name); +#endif dma_fence_put(&sde_fence->base); goto exit; } @@ -261,7 +277,9 @@ struct sde_fence_context *sde_fence_init(const char *name, uint32_t drm_id) return ERR_PTR(-ENOMEM); } +#ifdef CONFIG_FENCE_DEBUG strlcpy(ctx->name, name, ARRAY_SIZE(ctx->name)); +#endif ctx->drm_id = drm_id; kref_init(&ctx->kref); ctx->context = dma_fence_context_alloc(1); diff --git a/drivers/gpu/drm/msm/sde/sde_kms.c b/drivers/gpu/drm/msm/sde/sde_kms.c index c235a4feb398..cda8414ab897 100644 --- a/drivers/gpu/drm/msm/sde/sde_kms.c +++ b/drivers/gpu/drm/msm/sde/sde_kms.c @@ -367,9 +367,32 @@ static void _sde_debugfs_destroy(struct sde_kms *sde_kms) static int sde_kms_enable_vblank(struct msm_kms *kms, struct drm_crtc *crtc) { int ret = 0; + struct sde_kms *sde_kms; + struct msm_drm_private *priv; + struct sde_crtc *sde_crtc; + struct drm_encoder *drm_enc; + + sde_kms = to_sde_kms(kms); + priv = sde_kms->dev->dev_private; + sde_crtc = to_sde_crtc(crtc); SDE_ATRACE_BEGIN("sde_kms_enable_vblank"); + + if (sde_crtc->vblank_requested == false) { + SDE_ATRACE_BEGIN("sde_encoder_trigger_early_wakeup"); + drm_for_each_encoder(drm_enc, crtc->dev) + sde_encoder_trigger_early_wakeup(drm_enc); + + if (sde_kms->first_kickoff) { + sde_power_scale_reg_bus(&priv->phandle, + sde_kms->core_client, + VOTE_INDEX_HIGH, false); + } + SDE_ATRACE_END("sde_encoder_trigger_early_wakeup"); + } + ret = sde_crtc_vblank(crtc, true); + SDE_ATRACE_END("sde_kms_enable_vblank"); return ret; diff --git a/drivers/gpu/drm/msm/sde/sde_plane.c b/drivers/gpu/drm/msm/sde/sde_plane.c index 686d50391236..7716539d0bcd 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.c +++ b/drivers/gpu/drm/msm/sde/sde_plane.c @@ -3889,6 +3889,7 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane, struct drm_crtc *crtc; struct drm_framebuffer *fb; struct sde_rect src, dst; + bool is_rt; bool q16_data = true; int idx; @@ -4032,12 +4033,17 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane, _sde_plane_set_scanout(plane, pstate, &psde->pipe_cfg, fb); + is_rt = sde_crtc_get_client_type(crtc) != NRT_CLIENT; + if (is_rt != psde->is_rt_pipe) { + psde->is_rt_pipe = is_rt; + pstate->dirty |= SDE_PLANE_DIRTY_QOS; + } + /* early out if nothing dirty */ if (!pstate->dirty) return 0; pstate->pending = true; - psde->is_rt_pipe = (sde_crtc_get_client_type(crtc) != NRT_CLIENT); _sde_plane_set_qos_ctrl(plane, false, SDE_PLANE_QOS_PANIC_CTRL); /* update secure session flag */ @@ -4246,8 +4252,11 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane, &psde->sharp_cfg); } - _sde_plane_set_qos_lut(plane, fb); - _sde_plane_set_danger_lut(plane, fb); + if (pstate->dirty & (SDE_PLANE_DIRTY_QOS | SDE_PLANE_DIRTY_RECTS | + SDE_PLANE_DIRTY_FORMAT)) { + _sde_plane_set_qos_lut(plane, fb); + _sde_plane_set_danger_lut(plane, fb); + } if (plane->type != DRM_PLANE_TYPE_CURSOR) { _sde_plane_set_qos_ctrl(plane, true, SDE_PLANE_QOS_PANIC_CTRL); @@ -4256,7 +4265,8 @@ static int sde_plane_sspp_atomic_update(struct drm_plane *plane, _sde_plane_set_ts_prefill(plane, pstate); } - _sde_plane_set_qos_remap(plane); + if (pstate->dirty & SDE_PLANE_DIRTY_QOS) + _sde_plane_set_qos_remap(plane); /* clear dirty */ pstate->dirty = 0x0; diff --git a/drivers/gpu/drm/msm/sde/sde_plane.h b/drivers/gpu/drm/msm/sde/sde_plane.h index b128fb9475cc..efd262cd5234 100644 --- a/drivers/gpu/drm/msm/sde/sde_plane.h +++ b/drivers/gpu/drm/msm/sde/sde_plane.h @@ -96,7 +96,8 @@ struct sde_plane_rot_state { #define SDE_PLANE_DIRTY_VIG_GAMUT 0x20 #define SDE_PLANE_DIRTY_VIG_IGC 0x40 #define SDE_PLANE_DIRTY_DMA_IGC 0x80 -#define SDE_PLANE_DIRTY_DMA_GC 0x100 +#define SDE_PLANE_DIRTY_DMA_GC 0x100 +#define SDE_PLANE_DIRTY_QOS 0x200 #define SDE_PLANE_DIRTY_CP (SDE_PLANE_DIRTY_VIG_GAMUT |\ SDE_PLANE_DIRTY_VIG_IGC | SDE_PLANE_DIRTY_DMA_IGC |\ SDE_PLANE_DIRTY_DMA_GC) diff --git a/drivers/gpu/msm/adreno.c b/drivers/gpu/msm/adreno.c index 4547bb817c53..479f4c4dd1b9 100644 --- a/drivers/gpu/msm/adreno.c +++ b/drivers/gpu/msm/adreno.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include @@ -61,7 +60,6 @@ MODULE_PARM_DESC(swfdetect, "Enable soft fault detection"); #define KGSL_LOG_LEVEL_DEFAULT 3 -static void adreno_input_work(struct work_struct *work); static unsigned int counter_delta(struct kgsl_device *device, unsigned int reg, unsigned int *counter); @@ -102,8 +100,6 @@ static struct adreno_device device_3d0 = { .ft_policy = KGSL_FT_DEFAULT_POLICY, .ft_pf_policy = KGSL_FT_PAGEFAULT_DEFAULT_POLICY, .long_ib_detect = 1, - .input_work = __WORK_INITIALIZER(device_3d0.input_work, - adreno_input_work), .pwrctrl_flag = BIT(ADRENO_SPTP_PC_CTRL) | BIT(ADRENO_PPD_CTRL) | BIT(ADRENO_LM_CTRL) | BIT(ADRENO_HWCG_CTRL) | BIT(ADRENO_THROTTLING_CTRL), @@ -138,9 +134,6 @@ static unsigned int adreno_ft_regs_default[] = { /* Nice level for the higher priority GPU start thread */ int adreno_wake_nice = -7; -/* Number of milliseconds to stay active active after a wake on touch */ -unsigned int adreno_wake_timeout = 100; - /** * adreno_readreg64() - Read a 64bit register by getting its offset from the * offset array defined in gpudev node @@ -370,152 +363,6 @@ void adreno_fault_detect_stop(struct adreno_device *adreno_dev) adreno_dev->fast_hang_detect = 0; } -/* - * A workqueue callback responsible for actually turning on the GPU after a - * touch event. kgsl_pwrctrl_change_state(ACTIVE) is used without any - * active_count protection to avoid the need to maintain state. Either - * somebody will start using the GPU or the idle timer will fire and put the - * GPU back into slumber. - */ -static void adreno_input_work(struct work_struct *work) -{ - struct adreno_device *adreno_dev = container_of(work, - struct adreno_device, input_work); - struct kgsl_device *device = KGSL_DEVICE(adreno_dev); - - mutex_lock(&device->mutex); - - device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; - - /* - * Don't schedule adreno_start in a high priority workqueue, we are - * already in a workqueue which should be sufficient - */ - kgsl_pwrctrl_change_state(device, KGSL_STATE_ACTIVE); - - /* - * When waking up from a touch event we want to stay active long enough - * for the user to send a draw command. The default idle timer timeout - * is shorter than we want so go ahead and push the idle timer out - * further for this special case - */ - mod_timer(&device->idle_timer, - jiffies + msecs_to_jiffies(adreno_wake_timeout)); - mutex_unlock(&device->mutex); -} - -/* - * Process input events and schedule work if needed. At this point we are only - * interested in groking EV_ABS touchscreen events - */ -static void adreno_input_event(struct input_handle *handle, unsigned int type, - unsigned int code, int value) -{ - struct kgsl_device *device = handle->handler->private; - struct adreno_device *adreno_dev = ADRENO_DEVICE(device); - - /* Only consider EV_ABS (touch) events */ - if (type != EV_ABS) - return; - - /* - * Don't do anything if anything hasn't been rendered since we've been - * here before - */ - - if (device->flags & KGSL_FLAG_WAKE_ON_TOUCH) - return; - - /* - * If the device is in nap, kick the idle timer to make sure that we - * don't go into slumber before the first render. If the device is - * already in slumber schedule the wake. - */ - - if (device->state == KGSL_STATE_NAP) { - /* - * Set the wake on touch bit to keep from coming back here and - * keeping the device in nap without rendering - */ - - device->flags |= KGSL_FLAG_WAKE_ON_TOUCH; - - mod_timer(&device->idle_timer, - jiffies + device->pwrctrl.interval_timeout); - } else if (device->state == KGSL_STATE_SLUMBER) { - schedule_work(&adreno_dev->input_work); - } -} - -#ifdef CONFIG_INPUT -static int adreno_input_connect(struct input_handler *handler, - struct input_dev *dev, const struct input_device_id *id) -{ - struct input_handle *handle; - int ret; - - handle = kzalloc(sizeof(*handle), GFP_KERNEL); - if (handle == NULL) - return -ENOMEM; - - handle->dev = dev; - handle->handler = handler; - handle->name = handler->name; - - ret = input_register_handle(handle); - if (ret) { - kfree(handle); - return ret; - } - - ret = input_open_device(handle); - if (ret) { - input_unregister_handle(handle); - kfree(handle); - } - - return ret; -} - -static void adreno_input_disconnect(struct input_handle *handle) -{ - input_close_device(handle); - input_unregister_handle(handle); - kfree(handle); -} -#else -static int adreno_input_connect(struct input_handler *handler, - struct input_dev *dev, const struct input_device_id *id) -{ - return 0; -} -static void adreno_input_disconnect(struct input_handle *handle) {} -#endif - -/* - * We are only interested in EV_ABS events so only register handlers for those - * input devices that have EV_ABS events - */ -static const struct input_device_id adreno_input_ids[] = { - { - .flags = INPUT_DEVICE_ID_MATCH_EVBIT, - .evbit = { BIT_MASK(EV_ABS) }, - /* assumption: MT_.._X & MT_.._Y are in the same long */ - .absbit = { [BIT_WORD(ABS_MT_POSITION_X)] = - BIT_MASK(ABS_MT_POSITION_X) | - BIT_MASK(ABS_MT_POSITION_Y) }, - }, - { }, -}; - -static struct input_handler adreno_input_handler = { - .event = adreno_input_event, - .connect = adreno_input_connect, - .disconnect = adreno_input_disconnect, - .name = "kgsl", - .id_table = adreno_input_ids, -}; - /* * _soft_reset() - Soft reset GPU * @adreno_dev: Pointer to adreno device @@ -1147,20 +994,20 @@ static int adreno_of_get_power(struct adreno_device *adreno_dev, /* get pm-qos-active-latency, set it to default if not found */ if (of_property_read_u32(node, "qcom,pm-qos-active-latency", &device->pwrctrl.pm_qos_active_latency)) - device->pwrctrl.pm_qos_active_latency = 501; + device->pwrctrl.pm_qos_active_latency = 1000; /* get pm-qos-cpu-mask-latency, set it to default if not found */ if (of_property_read_u32(node, "qcom,l2pc-cpu-mask-latency", &device->pwrctrl.pm_qos_cpu_mask_latency)) - device->pwrctrl.pm_qos_cpu_mask_latency = 501; + device->pwrctrl.pm_qos_cpu_mask_latency = 1000; /* get pm-qos-wakeup-latency, set it to default if not found */ if (of_property_read_u32(node, "qcom,pm-qos-wakeup-latency", &device->pwrctrl.pm_qos_wakeup_latency)) - device->pwrctrl.pm_qos_wakeup_latency = 101; + device->pwrctrl.pm_qos_wakeup_latency = 100; if (of_property_read_u32(node, "qcom,idle-timeout", &timeout)) - timeout = 80; + timeout = 64; device->pwrctrl.interval_timeout = msecs_to_jiffies(timeout); @@ -1467,20 +1314,6 @@ static int adreno_probe(struct platform_device *pdev) "Failed to get gpuhtw LLC slice descriptor %ld\n", PTR_ERR(adreno_dev->gpuhtw_llc_slice)); -#ifdef CONFIG_INPUT - if (!device->pwrctrl.input_disable) { - adreno_input_handler.private = device; - /* - * It isn't fatal if we cannot register the input handler. Sad, - * perhaps, but not fatal - */ - if (input_register_handler(&adreno_input_handler)) { - adreno_input_handler.private = NULL; - KGSL_DRV_ERR(device, - "Unable to register the input handler\n"); - } - } -#endif out: if (status) { adreno_ringbuffer_close(adreno_dev); @@ -1532,10 +1365,6 @@ static int adreno_remove(struct platform_device *pdev) /* The memory is fading */ _adreno_free_memories(adreno_dev); -#ifdef CONFIG_INPUT - if (adreno_input_handler.private) - input_unregister_handler(&adreno_input_handler); -#endif adreno_sysfs_close(adreno_dev); adreno_coresight_remove(adreno_dev); @@ -4177,6 +4006,7 @@ static struct platform_driver adreno_platform_driver = { .name = DEVICE_3D_NAME, .pm = &kgsl_pm_ops, .of_match_table = adreno_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, } }; diff --git a/drivers/gpu/msm/adreno.h b/drivers/gpu/msm/adreno.h index 69f7235decbf..8bb4682cba32 100644 --- a/drivers/gpu/msm/adreno.h +++ b/drivers/gpu/msm/adreno.h @@ -475,7 +475,7 @@ enum gpu_coresight_sources { * @dispatcher: Container for adreno GPU dispatcher * @pwron_fixup: Command buffer to run a post-power collapse shader workaround * @pwron_fixup_dwords: Number of dwords in the command buffer - * @input_work: Work struct for turning on the GPU after a touch event + * @pwr_on_work: Work struct for turning on the GPU * @busy_data: Struct holding GPU VBIF busy stats * @ram_cycles_lo: Number of DDR clock cycles for the monitor session (Only * DDR channel 0 read cycles in case of GBIF) @@ -555,7 +555,7 @@ struct adreno_device { struct adreno_dispatcher dispatcher; struct kgsl_memdesc pwron_fixup; unsigned int pwron_fixup_dwords; - struct work_struct input_work; + struct work_struct pwr_on_work; struct adreno_busy_data busy_data; unsigned int ram_cycles_lo; unsigned int ram_cycles_lo_ch1_read; @@ -1128,7 +1128,6 @@ extern struct adreno_gpudev adreno_a5xx_gpudev; extern struct adreno_gpudev adreno_a6xx_gpudev; extern int adreno_wake_nice; -extern unsigned int adreno_wake_timeout; int adreno_start(struct kgsl_device *device, int priority); int adreno_soft_reset(struct kgsl_device *device); diff --git a/drivers/gpu/msm/adreno_debugfs.c b/drivers/gpu/msm/adreno_debugfs.c index 2dd651a446b1..7d19d1352b80 100644 --- a/drivers/gpu/msm/adreno_debugfs.c +++ b/drivers/gpu/msm/adreno_debugfs.c @@ -131,11 +131,13 @@ static void sync_event_print(struct seq_file *s, break; } case KGSL_CMD_SYNCPOINT_TYPE_FENCE: { +#ifdef CONFIG_FENCE_DEBUG int i; for (i = 0; i < sync_event->info.num_fences; i++) seq_printf(s, "sync: %s", sync_event->info.fences[i].name); +#endif break; } default: diff --git a/drivers/gpu/msm/adreno_dispatch.c b/drivers/gpu/msm/adreno_dispatch.c index 4e4be1e64cef..d4e091adc5b2 100644 --- a/drivers/gpu/msm/adreno_dispatch.c +++ b/drivers/gpu/msm/adreno_dispatch.c @@ -1167,12 +1167,6 @@ static inline int _verify_cmdobj(struct kgsl_device_private *dev_priv, &ADRENO_CONTEXT(context)->base, ib) == false) return -EINVAL; - /* - * Clear the wake on touch bit to indicate an IB has - * been submitted since the last time we set it. - * But only clear it when we have rendering commands. - */ - device->flags &= ~KGSL_FLAG_WAKE_ON_TOUCH; } /* A3XX does not have support for drawobj profiling */ diff --git a/drivers/gpu/msm/adreno_iommu.c b/drivers/gpu/msm/adreno_iommu.c index 0fb74151ca0a..c6cf3811bb35 100644 --- a/drivers/gpu/msm/adreno_iommu.c +++ b/drivers/gpu/msm/adreno_iommu.c @@ -802,21 +802,15 @@ static int _set_pagetable_cpu(struct adreno_ringbuffer *rb, static int _set_pagetable_gpu(struct adreno_ringbuffer *rb, struct kgsl_pagetable *new_pt) { + static unsigned int link[PAGE_SIZE / sizeof(unsigned int)] + ____cacheline_aligned_in_smp; struct adreno_device *adreno_dev = ADRENO_RB_DEVICE(rb); - unsigned int *link = NULL, *cmds; + unsigned int *cmds = link; int result; - link = kmalloc(PAGE_SIZE, GFP_KERNEL); - if (link == NULL) - return -ENOMEM; - - cmds = link; - /* If we are in a fault the MMU will be reset soon */ - if (test_bit(ADRENO_DEVICE_FAULT, &adreno_dev->priv)) { - kfree(link); + if (test_bit(ADRENO_DEVICE_FAULT, &adreno_dev->priv)) return 0; - } cmds += adreno_iommu_set_pt_generate_cmds(rb, cmds, new_pt); @@ -838,7 +832,6 @@ static int _set_pagetable_gpu(struct adreno_ringbuffer *rb, KGSL_CMD_FLAGS_PMODE, link, (unsigned int)(cmds - link)); - kfree(link); return result; } diff --git a/drivers/gpu/msm/adreno_sysfs.c b/drivers/gpu/msm/adreno_sysfs.c index 407c05b79bd3..3b2eb821a92e 100644 --- a/drivers/gpu/msm/adreno_sysfs.c +++ b/drivers/gpu/msm/adreno_sysfs.c @@ -623,7 +623,6 @@ static ADRENO_SYSFS_BOOL(gpu_llc_slice_enable); static ADRENO_SYSFS_BOOL(gpuhtw_llc_slice_enable); static DEVICE_INT_ATTR(wake_nice, 0644, adreno_wake_nice); -static DEVICE_INT_ATTR(wake_timeout, 0644, adreno_wake_timeout); static ADRENO_SYSFS_BOOL(sptp_pc); static ADRENO_SYSFS_BOOL(lm); @@ -647,7 +646,6 @@ static const struct device_attribute *_attr_list[] = { &adreno_attr_ft_long_ib_detect.attr, &adreno_attr_ft_hang_intr_status.attr, &dev_attr_wake_nice.attr, - &dev_attr_wake_timeout.attr, &adreno_attr_sptp_pc.attr, &adreno_attr_lm.attr, &adreno_attr_preemption.attr, diff --git a/drivers/gpu/msm/kgsl_debugfs.c b/drivers/gpu/msm/kgsl_debugfs.c index 834706a973d2..7d08b2fbc393 100644 --- a/drivers/gpu/msm/kgsl_debugfs.c +++ b/drivers/gpu/msm/kgsl_debugfs.c @@ -410,8 +410,11 @@ void kgsl_process_init_debugfs(struct kgsl_process_private *private) */ if (IS_ERR_OR_NULL(private->debug_root)) { + /* WARN((private->debug_root == NULL), "Unable to create debugfs dir for %s\n", name); + */ + pr_warn("Unable to create debugfs dir for %s\n", name); private->debug_root = NULL; return; } diff --git a/drivers/gpu/msm/kgsl_device.h b/drivers/gpu/msm/kgsl_device.h index 01bc3ffe7271..b3e5a27350df 100644 --- a/drivers/gpu/msm/kgsl_device.h +++ b/drivers/gpu/msm/kgsl_device.h @@ -68,8 +68,7 @@ enum kgsl_event_results { KGSL_EVENT_CANCELLED = 2, }; -#define KGSL_FLAG_WAKE_ON_TOUCH BIT(0) -#define KGSL_FLAG_SPARSE BIT(1) +#define KGSL_FLAG_SPARSE BIT(0) /* * "list" of event types for ftrace symbolic magic diff --git a/drivers/gpu/msm/kgsl_drawobj.c b/drivers/gpu/msm/kgsl_drawobj.c index 05c41362e11d..f36a8f753a85 100644 --- a/drivers/gpu/msm/kgsl_drawobj.c +++ b/drivers/gpu/msm/kgsl_drawobj.c @@ -43,6 +43,7 @@ static struct kmem_cache *memobjs_cache; static struct kmem_cache *sparseobjs_cache; +#ifdef CONFIG_FENCE_DEBUG static void free_fence_names(struct kgsl_drawobj_sync *syncobj) { unsigned int i; @@ -54,6 +55,7 @@ static void free_fence_names(struct kgsl_drawobj_sync *syncobj) kfree(event->info.fences); } } +#endif void kgsl_drawobj_destroy_object(struct kref *kref) { @@ -66,7 +68,9 @@ void kgsl_drawobj_destroy_object(struct kref *kref) switch (drawobj->type) { case SYNCOBJ_TYPE: syncobj = SYNCOBJ(drawobj); +#ifdef CONFIG_FENCE_DEBUG free_fence_names(syncobj); +#endif kfree(syncobj->synclist); kfree(syncobj); break; @@ -107,12 +111,14 @@ void kgsl_dump_syncpoints(struct kgsl_device *device, break; } case KGSL_CMD_SYNCPOINT_TYPE_FENCE: { +#ifdef CONFIG_FENCE_DEBUG int j; struct event_fence_info *info = &event->info; for (j = 0; j < info->num_fences; j++) dev_err(device->dev, "[%d] fence: %s\n", i, info->fences[j].name); +#endif break; } } @@ -164,12 +170,14 @@ static void syncobj_timer(unsigned long data) i, event->context->id, event->timestamp); break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: { +#ifdef CONFIG_FENCE_DEBUG int j; struct event_fence_info *info = &event->info; for (j = 0; j < info->num_fences; j++) dev_err(device->dev, " [%u] FENCE %s\n", i, info->fences[j].name); +#endif break; } } @@ -355,11 +363,13 @@ EXPORT_SYMBOL(kgsl_drawobj_destroy); static bool drawobj_sync_fence_func(void *priv) { struct kgsl_drawobj_sync_event *event = priv; +#ifdef CONFIG_FENCE_DEBUG int i; for (i = 0; i < event->info.num_fences; i++) trace_syncpoint_fence_expire(event->syncobj, event->info.fences[i].name); +#endif /* * Only call kgsl_drawobj_put() if it's not marked for cancellation @@ -423,8 +433,10 @@ static int drawobj_add_sync_fence(struct kgsl_device *device, return ret; } +#ifdef CONFIG_FENCE_DEBUG for (i = 0; i < event->info.num_fences; i++) trace_syncpoint_fence(syncobj, event->info.fences[i].name); +#endif return 0; } @@ -518,20 +530,24 @@ int kgsl_drawobj_sync_add_sync(struct kgsl_device *device, struct kgsl_cmd_syncpoint *sync) { void *priv; - int ret, psize; + int psize; struct kgsl_drawobj *drawobj = DRAWOBJ(syncobj); int (*func)(struct kgsl_device *device, struct kgsl_drawobj_sync *syncobj, void *priv); + struct kgsl_cmd_syncpoint_timestamp sync_timestamp; + struct kgsl_cmd_syncpoint_fence sync_fence; switch (sync->type) { case KGSL_CMD_SYNCPOINT_TYPE_TIMESTAMP: psize = sizeof(struct kgsl_cmd_syncpoint_timestamp); func = drawobj_add_sync_timestamp; + priv = &sync_timestamp; break; case KGSL_CMD_SYNCPOINT_TYPE_FENCE: psize = sizeof(struct kgsl_cmd_syncpoint_fence); func = drawobj_add_sync_fence; + priv = &sync_fence; break; default: KGSL_DRV_ERR(device, @@ -547,19 +563,10 @@ int kgsl_drawobj_sync_add_sync(struct kgsl_device *device, return -EINVAL; } - priv = kzalloc(sync->size, GFP_KERNEL); - if (priv == NULL) - return -ENOMEM; - - if (copy_from_user(priv, sync->priv, sync->size)) { - kfree(priv); + if (copy_from_user(priv, sync->priv, sync->size)) return -EFAULT; - } - ret = func(device, syncobj, priv); - kfree(priv); - - return ret; + return func(device, syncobj, priv); } static void add_profiling_buffer(struct kgsl_device *device, diff --git a/drivers/gpu/msm/kgsl_drawobj.h b/drivers/gpu/msm/kgsl_drawobj.h index bd32f5e503a7..79174751b944 100644 --- a/drivers/gpu/msm/kgsl_drawobj.h +++ b/drivers/gpu/msm/kgsl_drawobj.h @@ -107,12 +107,16 @@ struct kgsl_drawobj_sync { #define KGSL_FENCE_NAME_LEN 74 +#ifdef CONFIG_FENCE_DEBUG struct fence_info { char name[KGSL_FENCE_NAME_LEN]; }; +#endif struct event_fence_info { +#ifdef CONFIG_FENCE_DEBUG struct fence_info *fences; +#endif int num_fences; }; diff --git a/drivers/gpu/msm/kgsl_ioctl.c b/drivers/gpu/msm/kgsl_ioctl.c index 9b02e1993a09..9fd87c2d26f4 100644 --- a/drivers/gpu/msm/kgsl_ioctl.c +++ b/drivers/gpu/msm/kgsl_ioctl.c @@ -17,6 +17,7 @@ #include #include "kgsl_device.h" #include "kgsl_sync.h" +#include "adreno.h" static const struct kgsl_ioctl kgsl_ioctl_funcs[] = { KGSL_IOCTL_FUNC(IOCTL_KGSL_DEVICE_GETPROPERTY, @@ -168,6 +169,7 @@ long kgsl_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { struct kgsl_device_private *dev_priv = filep->private_data; struct kgsl_device *device = dev_priv->device; + struct adreno_device *adreno_dev = ADRENO_DEVICE(device); long ret; ret = kgsl_ioctl_helper(filep, cmd, arg, kgsl_ioctl_funcs, diff --git a/drivers/gpu/msm/kgsl_pwrctrl.h b/drivers/gpu/msm/kgsl_pwrctrl.h index fc07ee5ff4fc..8dede9257bbf 100644 --- a/drivers/gpu/msm/kgsl_pwrctrl.h +++ b/drivers/gpu/msm/kgsl_pwrctrl.h @@ -56,9 +56,9 @@ /* * The effective duration of qos request in usecs at queue time. * After timeout, qos request is cancelled automatically. - * Kept 80ms default, inline with default GPU idle time. + * Kept 64ms default, inline with default GPU idle time. */ -#define KGSL_L2PC_QUEUE_TIMEOUT (80 * 1000) +#define KGSL_L2PC_QUEUE_TIMEOUT (64 * 1000) /* * The effective duration of qos request in usecs at wakeup time. diff --git a/drivers/gpu/msm/kgsl_sync.c b/drivers/gpu/msm/kgsl_sync.c index c353b912105f..9e05b8771caf 100644 --- a/drivers/gpu/msm/kgsl_sync.c +++ b/drivers/gpu/msm/kgsl_sync.c @@ -318,32 +318,40 @@ static const char *kgsl_sync_fence_driver_name(struct dma_fence *fence) static const char *kgsl_sync_timeline_name(struct dma_fence *fence) { +#ifdef CONFIG_FENCE_DEBUG struct kgsl_sync_fence *kfence = (struct kgsl_sync_fence *)fence; struct kgsl_sync_timeline *ktimeline = kfence->parent; return ktimeline->name; +#else + return "kgsl_sync_timeline"; +#endif } int kgsl_sync_timeline_create(struct kgsl_context *context) { struct kgsl_sync_timeline *ktimeline; +#ifdef CONFIG_FENCE_DEBUG /* * Generate a name which includes the thread name, thread id, process * name, process id, and context id. This makes it possible to * identify the context of a timeline in the sync dump. */ char ktimeline_name[sizeof(ktimeline->name)] = {}; +#endif /* Put context when timeline is released */ if (!_kgsl_context_get(context)) return -ENOENT; +#ifdef CONFIG_FENCE_DEBUG snprintf(ktimeline_name, sizeof(ktimeline_name), "%s_%d-%.15s(%d)-%.15s(%d)", context->device->name, context->id, current->group_leader->comm, current->group_leader->pid, current->comm, current->pid); +#endif ktimeline = kzalloc(sizeof(*ktimeline), GFP_KERNEL); if (ktimeline == NULL) { @@ -352,7 +360,9 @@ int kgsl_sync_timeline_create(struct kgsl_context *context) } kref_init(&ktimeline->kref); +#ifdef CONFIG_FENCE_DEBUG strlcpy(ktimeline->name, ktimeline_name, KGSL_TIMELINE_NAME_LEN); +#endif ktimeline->fence_context = dma_fence_context_alloc(1); ktimeline->last_timestamp = 0; INIT_LIST_HEAD(&ktimeline->child_list_head); @@ -440,6 +450,7 @@ static void kgsl_sync_fence_callback(struct dma_fence *fence, } } +#ifdef CONFIG_FENCE_DEBUG static void kgsl_get_fence_names(struct dma_fence *fence, struct event_fence_info *info_ptr) { @@ -485,6 +496,7 @@ static void kgsl_get_fence_names(struct dma_fence *fence, } } } +#endif struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd, bool (*func)(void *priv), void *priv, struct event_fence_info *info_ptr) @@ -497,6 +509,11 @@ struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd, if (fence == NULL) return ERR_PTR(-EINVAL); + if (test_bit(DMA_FENCE_FLAG_SIGNALED_BIT, &fence->flags)) { + dma_fence_put(fence); + return NULL; + } + /* create the callback */ kcb = kzalloc(sizeof(*kcb), GFP_ATOMIC); if (kcb == NULL) { @@ -508,7 +525,9 @@ struct kgsl_sync_fence_cb *kgsl_sync_fence_async_wait(int fd, kcb->priv = priv; kcb->func = func; +#ifdef CONFIG_FENCE_DEBUG kgsl_get_fence_names(fence, info_ptr); +#endif /* if status then error or signaled */ status = dma_fence_add_callback(fence, &kcb->fence_cb, diff --git a/drivers/gpu/msm/kgsl_sync.h b/drivers/gpu/msm/kgsl_sync.h index e970c9451058..07732f580e9d 100644 --- a/drivers/gpu/msm/kgsl_sync.h +++ b/drivers/gpu/msm/kgsl_sync.h @@ -32,7 +32,9 @@ */ struct kgsl_sync_timeline { struct kref kref; +#ifdef CONFIG_FENCE_DEBUG char name[KGSL_TIMELINE_NAME_LEN]; +#endif u64 fence_context; diff --git a/drivers/i2c/busses/i2c-qcom-geni.c b/drivers/i2c/busses/i2c-qcom-geni.c index 768585782484..2635cac198bf 100644 --- a/drivers/i2c/busses/i2c-qcom-geni.c +++ b/drivers/i2c/busses/i2c-qcom-geni.c @@ -1114,6 +1114,7 @@ static struct platform_driver geni_i2c_driver = { .name = "i2c_geni", .pm = &geni_i2c_pm_ops, .of_match_table = geni_i2c_dt_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/i2c/i2c-core-base.c b/drivers/i2c/i2c-core-base.c index 7b961c9c62ef..63e64938736b 100644 --- a/drivers/i2c/i2c-core-base.c +++ b/drivers/i2c/i2c-core-base.c @@ -766,6 +766,9 @@ i2c_new_device(struct i2c_adapter *adap, struct i2c_board_info const *info) client->dev.of_node = info->of_node; client->dev.fwnode = info->fwnode; + if (client->flags & I2C_CLIENT_ASYNC_SUSPEND) + device_enable_async_suspend(&client->dev); + i2c_dev_set_name(adap, client); if (info->properties) { diff --git a/drivers/i2c/i2c-core-of.c b/drivers/i2c/i2c-core-of.c index 8d474bb1dc15..8884f8ed0a25 100644 --- a/drivers/i2c/i2c-core-of.c +++ b/drivers/i2c/i2c-core-of.c @@ -73,6 +73,9 @@ static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap, if (of_get_property(node, "wakeup-source", NULL)) info.flags |= I2C_CLIENT_WAKE; + if (of_property_read_bool(node, "async-suspend")) + info.flags |= I2C_CLIENT_ASYNC_SUSPEND; + result = i2c_new_device(adap, &info); if (result == NULL) { dev_err(&adap->dev, "of_i2c: Failure registering %pOF\n", node); diff --git a/drivers/iio/adc/qcom-spmi-adc5.c b/drivers/iio/adc/qcom-spmi-adc5.c index a5680d8260f1..1370c7ebd213 100644 --- a/drivers/iio/adc/qcom-spmi-adc5.c +++ b/drivers/iio/adc/qcom-spmi-adc5.c @@ -763,12 +763,10 @@ static const struct adc_channels adc_chans_pmic5[ADC_MAX_CHANNEL] = { SCALE_HW_CALIB_PM5_SMB_TEMP) [ADC_AMUX_THM3] = ADC_CHAN_TEMP("amux_thm3", 1, SCALE_HW_CALIB_PM5_SMB_TEMP) - [ADC_GPIO1_PU2] = ADC_CHAN_TEMP("gpio1_pu2", 1, - SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC_GPIO2_PU2] = ADC_CHAN_TEMP("gpio2_pu2", 1, - SCALE_HW_CALIB_THERM_100K_PULLUP) - [ADC_GPIO3_PU2] = ADC_CHAN_TEMP("gpio3_pu2", 1, - SCALE_HW_CALIB_THERM_100K_PULLUP) + [ADC_GPIO1_PU2] = ADC_CHAN_VOLT("gpio1_pu2", 1, + SCALE_HW_CALIB_DEFAULT) + [ADC_GPIO2_PU2] = ADC_CHAN_VOLT("gpio2_pu2", 1, + SCALE_HW_CALIB_DEFAULT) [ADC_GPIO4_PU2] = ADC_CHAN_TEMP("gpio4_pu2", 1, SCALE_HW_CALIB_THERM_100K_PULLUP) }; diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 724715e4f8bc..f28a8cee7796 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -213,6 +213,8 @@ source "drivers/input/misc/Kconfig" source "drivers/input/rmi4/Kconfig" +source "drivers/input/fingerprint/Kconfig" + endif menu "Hardware I/O ports" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index f0351af763bd..7819a2ee5a48 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -25,6 +25,7 @@ obj-$(CONFIG_INPUT_JOYSTICK) += joystick/ obj-$(CONFIG_INPUT_TABLET) += tablet/ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ obj-$(CONFIG_INPUT_MISC) += misc/ +obj-$(CONFIG_INPUT_FINGERPRINT) += fingerprint/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o diff --git a/drivers/input/fingerprint/Kconfig b/drivers/input/fingerprint/Kconfig new file mode 100644 index 000000000000..f21f3a69a946 --- /dev/null +++ b/drivers/input/fingerprint/Kconfig @@ -0,0 +1,16 @@ +# +# Fingerprint driver configuration +# +menuconfig INPUT_FINGERPRINT + bool "Fingerprints" + help + Say Y here, and a list of supported fingerprints will be displayed. + This option doesn't affect the kernel. + + If unsure, say Y. + +if INPUT_FINGERPRINT + +source "drivers/input/fingerprint/goodix_ta/Kconfig" + +endif diff --git a/drivers/input/fingerprint/Makefile b/drivers/input/fingerprint/Makefile new file mode 100644 index 000000000000..e06550637994 --- /dev/null +++ b/drivers/input/fingerprint/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the fingerprint drivers. +# + +# Each configuration option enables a list of files. + +obj-$(CONFIG_FINGERPRINT_GOODIX_TA) += goodix_ta/ diff --git a/drivers/input/fingerprint/goodix_ta/Kconfig b/drivers/input/fingerprint/goodix_ta/Kconfig new file mode 100644 index 000000000000..34b155459ad3 --- /dev/null +++ b/drivers/input/fingerprint/goodix_ta/Kconfig @@ -0,0 +1,10 @@ +config FINGERPRINT_GOODIX_TA + tristate "Finger print card goodix" + depends on INPUT_FINGERPRINT + help + Say Y here to enable support for retrieving self-test reports. + + If unsure, say N. + + To compile this driver as a module, choose M here. + diff --git a/drivers/input/fingerprint/goodix_ta/Makefile b/drivers/input/fingerprint/goodix_ta/Makefile new file mode 100644 index 000000000000..43929c138f64 --- /dev/null +++ b/drivers/input/fingerprint/goodix_ta/Makefile @@ -0,0 +1 @@ +obj-$(CONFIG_FINGERPRINT_GOODIX_TA) += gf_spi.o platform.o netlink.o diff --git a/drivers/input/fingerprint/goodix_ta/gf_spi.c b/drivers/input/fingerprint/goodix_ta/gf_spi.c new file mode 100644 index 000000000000..914b5b336491 --- /dev/null +++ b/drivers/input/fingerprint/goodix_ta/gf_spi.c @@ -0,0 +1,1060 @@ +/* + * TEE driver for goodix fingerprint sensor + * Copyright (C) 2016 Goodix + * Copyright (C) 2019 XiaoMi, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + */ +#define DEBUG +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#define GOODIX_DRM_INTERFACE_WA + +#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 GOODIX_DRM_INTERFACE_WA +#include +#endif + +#include "gf_spi.h" + +#if defined(USE_SPI_BUS) +#include +#include +#elif defined(USE_PLATFORM_BUS) +#include +#endif + +#define VER_MAJOR 1 +#define VER_MINOR 2 +#define PATCH_LEVEL 1 + +#define WAKELOCK_HOLD_TIME 2000 /* in ms */ +#define FP_UNLOCK_REJECTION_TIMEOUT (WAKELOCK_HOLD_TIME - 500) + +#define GF_SPIDEV_NAME "goodix,fingerprint" +/*device name after register in charater*/ +#define GF_DEV_NAME "goodix_fp" +#define GF_INPUT_NAME "uinput-goodix" /*"goodix_fp" */ + +#define CHRD_DRIVER_NAME "goodix_fp_spi" +#define CLASS_NAME "goodix_fp" + +#define N_SPI_MINORS 32 /* ... up to 256 */ + + +static int SPIDEV_MAJOR; + +static DECLARE_BITMAP(minors, N_SPI_MINORS); +static LIST_HEAD(device_list); +static DEFINE_MUTEX(device_list_lock); +static struct wakeup_source fp_wakelock; +static struct gf_dev gf; + +struct gf_key_map maps[] = { + { EV_KEY, GF_KEY_INPUT_HOME }, + { EV_KEY, GF_KEY_INPUT_MENU }, + { EV_KEY, GF_KEY_INPUT_BACK }, + { EV_KEY, GF_KEY_INPUT_POWER }, +#if defined(SUPPORT_NAV_EVENT) + { EV_KEY, GF_NAV_INPUT_UP }, + { EV_KEY, GF_NAV_INPUT_DOWN }, + { EV_KEY, GF_NAV_INPUT_RIGHT }, + { EV_KEY, GF_NAV_INPUT_LEFT }, + { EV_KEY, GF_KEY_INPUT_CAMERA }, + { EV_KEY, GF_NAV_INPUT_CLICK }, + { EV_KEY, GF_NAV_INPUT_DOUBLE_CLICK }, + { EV_KEY, GF_NAV_INPUT_LONG_PRESS }, + { EV_KEY, GF_NAV_INPUT_HEAVY }, +#endif +}; + +static void gf_enable_irq(struct gf_dev *gf_dev) +{ + if (gf_dev->irq_enabled) { + pr_warn("IRQ has been enabled.\n"); + } else { + enable_irq(gf_dev->irq); + gf_dev->irq_enabled = 1; + } +} + +static void gf_disable_irq(struct gf_dev *gf_dev) +{ + if (gf_dev->irq_enabled) { + gf_dev->irq_enabled = 0; + disable_irq(gf_dev->irq); + } else { + pr_warn("IRQ has been disabled.\n"); + } +} + +#ifdef AP_CONTROL_CLK +static long spi_clk_max_rate(struct clk *clk, unsigned long rate) +{ + long lowest_available, nearest_low, step_size, cur; + long step_direction = -1; + long guess = rate; + int max_steps = 10; + cur = clk_round_rate(clk, rate); + + if (cur == rate) { + return rate; + } + + /* if we got here then: cur > rate */ + lowest_available = clk_round_rate(clk, 0); + + if (lowest_available > rate) { + return -EINVAL; + } + + step_size = (rate - lowest_available) >> 1; + nearest_low = lowest_available; + + while (max_steps-- && step_size) { + guess += step_size * step_direction; + cur = clk_round_rate(clk, guess); + + if ((cur < rate) && (cur > nearest_low)) { + nearest_low = cur; + } + + /* + * if we stepped too far, then start stepping in the other + * direction with half the step size + */ + if (((cur > rate) && (step_direction > 0)) + || ((cur < rate) && (step_direction < 0))) { + step_direction = -step_direction; + step_size >>= 1; + } + } + + return nearest_low; +} + +static void spi_clock_set(struct gf_dev *gf_dev, int speed) +{ + long rate; + int rc; + rate = spi_clk_max_rate(gf_dev->core_clk, speed); + + if (rate < 0) { + pr_debug("%s: no match found for requested clock frequency:%d", + __func__, speed); + return; + } + + rc = clk_set_rate(gf_dev->core_clk, rate); +} + +static int gfspi_ioctl_clk_init(struct gf_dev *data) +{ + pr_debug("%s: enter\n", __func__); + data->clk_enabled = 0; + data->core_clk = clk_get(&data->spi->dev, "core_clk"); + + if (IS_ERR_OR_NULL(data->core_clk)) { + pr_err("%s: fail to get core_clk\n", __func__); + return -EPERM; + } + + data->iface_clk = clk_get(&data->spi->dev, "iface_clk"); + + if (IS_ERR_OR_NULL(data->iface_clk)) { + pr_err("%s: fail to get iface_clk\n", __func__); + clk_put(data->core_clk); + data->core_clk = NULL; + return -ENOENT; + } + + return 0; +} + +static int gfspi_ioctl_clk_enable(struct gf_dev *data) +{ + int err; + pr_debug("%s: enter\n", __func__); + + if (data->clk_enabled) { + return 0; + } + + err = clk_prepare_enable(data->core_clk); + + if (err) { + pr_err("%s: fail to enable core_clk\n", __func__); + return -EPERM; + } + + err = clk_prepare_enable(data->iface_clk); + + if (err) { + pr_err("%s: fail to enable iface_clk\n", __func__); + clk_disable_unprepare(data->core_clk); + return -ENOENT; + } + + data->clk_enabled = 1; + return 0; +} + +static int gfspi_ioctl_clk_disable(struct gf_dev *data) +{ + pr_debug("%s: enter\n", __func__); + + if (!data->clk_enabled) { + return 0; + } + + clk_disable_unprepare(data->core_clk); + clk_disable_unprepare(data->iface_clk); + data->clk_enabled = 0; + return 0; +} + +static int gfspi_ioctl_clk_uninit(struct gf_dev *data) +{ + pr_debug("%s: enter\n", __func__); + + if (data->clk_enabled) { + gfspi_ioctl_clk_disable(data); + } + + if (!IS_ERR_OR_NULL(data->core_clk)) { + clk_put(data->core_clk); + data->core_clk = NULL; + } + + if (!IS_ERR_OR_NULL(data->iface_clk)) { + clk_put(data->iface_clk); + data->iface_clk = NULL; + } + + return 0; +} +#endif + +static void nav_event_input(struct gf_dev *gf_dev, gf_nav_event_t nav_event) +{ + uint32_t nav_input = 0; + + switch (nav_event) { + case GF_NAV_FINGER_DOWN: + pr_debug("%s nav finger down\n", __func__); + break; + + case GF_NAV_FINGER_UP: + pr_debug("%s nav finger up\n", __func__); + break; + + case GF_NAV_DOWN: + nav_input = GF_NAV_INPUT_DOWN; + pr_debug("%s nav down\n", __func__); + break; + + case GF_NAV_UP: + nav_input = GF_NAV_INPUT_UP; + pr_debug("%s nav up\n", __func__); + break; + + case GF_NAV_LEFT: + nav_input = GF_NAV_INPUT_LEFT; + pr_debug("%s nav left\n", __func__); + break; + + case GF_NAV_RIGHT: + nav_input = GF_NAV_INPUT_RIGHT; + pr_debug("%s nav right\n", __func__); + break; + + case GF_NAV_CLICK: + nav_input = GF_NAV_INPUT_CLICK; + pr_debug("%s nav click\n", __func__); + break; + + case GF_NAV_HEAVY: + nav_input = GF_NAV_INPUT_HEAVY; + pr_debug("%s nav heavy\n", __func__); + break; + + case GF_NAV_LONG_PRESS: + nav_input = GF_NAV_INPUT_LONG_PRESS; + pr_debug("%s nav long press\n", __func__); + break; + + case GF_NAV_DOUBLE_CLICK: + nav_input = GF_NAV_INPUT_DOUBLE_CLICK; + pr_debug("%s nav double click\n", __func__); + break; + + default: + pr_warn("%s unknown nav event: %d\n", __func__, nav_event); + break; + } + + if ((nav_event != GF_NAV_FINGER_DOWN) && (nav_event != GF_NAV_FINGER_UP)) { + input_report_key(gf_dev->input, nav_input, 1); + input_sync(gf_dev->input); + input_report_key(gf_dev->input, nav_input, 0); + input_sync(gf_dev->input); + } +} + + +static void gf_kernel_key_input(struct gf_dev *gf_dev, struct gf_key *gf_key) +{ + uint32_t key_input = 0; + + if (GF_KEY_HOME == gf_key->key) { + key_input = GF_KEY_INPUT_HOME; + } else if (GF_KEY_POWER == gf_key->key) { + key_input = GF_KEY_INPUT_POWER; + } else if (GF_KEY_CAMERA == gf_key->key) { + key_input = GF_KEY_INPUT_CAMERA; + } else { + /* add special key define */ + key_input = gf_key->key; + } + + pr_debug("%s: received key event[%d], key=%d, value=%d\n", + __func__, key_input, gf_key->key, gf_key->value); + + if ((GF_KEY_POWER == gf_key->key || GF_KEY_CAMERA == gf_key->key) + && (gf_key->value == 1)) { + input_report_key(gf_dev->input, key_input, 1); + input_sync(gf_dev->input); + input_report_key(gf_dev->input, key_input, 0); + input_sync(gf_dev->input); + } + + if (GF_KEY_HOME == gf_key->key) { + input_report_key(gf_dev->input, key_input, gf_key->value); + input_sync(gf_dev->input); + } +} + +static long gf_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct gf_dev *gf_dev = &gf; + struct gf_key gf_key; +#if defined(SUPPORT_NAV_EVENT) + gf_nav_event_t nav_event = GF_NAV_NONE; +#endif + int retval = 0; + u8 netlink_route = NETLINK_TEST; + struct gf_ioc_chip_info info; + + if (_IOC_TYPE(cmd) != GF_IOC_MAGIC) { + return -ENODEV; + } + + if (_IOC_DIR(cmd) & _IOC_READ) { + retval = !access_ok(VERIFY_WRITE, (void __user *)arg, _IOC_SIZE(cmd)); + } else if (_IOC_DIR(cmd) & _IOC_WRITE) { + retval = !access_ok(VERIFY_READ, (void __user *)arg, _IOC_SIZE(cmd)); + } + + if (retval) { + return -EFAULT; + } + + if (gf_dev->device_available == 0) { + if ((cmd == GF_IOC_ENABLE_POWER) || (cmd == GF_IOC_DISABLE_POWER)) { + pr_debug("power cmd\n"); + } else { + pr_debug("get cmd %d, but sensor is power off currently.\n", _IOC_NR(cmd)); + return -ENODEV; + } + } + + switch (cmd) { + case GF_IOC_INIT: + pr_debug("%s GF_IOC_INIT\n", __func__); + + if (copy_to_user((void __user *)arg, (void *)&netlink_route, sizeof(u8))) { + retval = -EFAULT; + break; + } + + break; + + case GF_IOC_EXIT: + pr_debug("%s GF_IOC_EXIT\n", __func__); + break; + + case GF_IOC_DISABLE_IRQ: + pr_debug("%s GF_IOC_DISABEL_IRQ\n", __func__); + gf_disable_irq(gf_dev); + break; + + case GF_IOC_ENABLE_IRQ: + pr_debug("%s GF_IOC_ENABLE_IRQ\n", __func__); + gf_enable_irq(gf_dev); + break; + + case GF_IOC_RESET: + pr_debug("%s GF_IOC_RESET.\n", __func__); + gf_hw_reset(gf_dev, 3); + break; + + case GF_IOC_INPUT_KEY_EVENT: + if (copy_from_user(&gf_key, (struct gf_key *)arg, sizeof(struct gf_key))) { + pr_debug("Failed to copy input key event from user to kernel\n"); + retval = -EFAULT; + break; + } + + gf_kernel_key_input(gf_dev, &gf_key); + break; +#if defined(SUPPORT_NAV_EVENT) + + case GF_IOC_NAV_EVENT: + pr_debug("%s GF_IOC_NAV_EVENT\n", __func__); + + if (copy_from_user(&nav_event, (gf_nav_event_t *)arg, sizeof(gf_nav_event_t))) { + pr_debug("Failed to copy nav event from user to kernel\n"); + retval = -EFAULT; + break; + } + + nav_event_input(gf_dev, nav_event); + break; +#endif + + case GF_IOC_ENABLE_SPI_CLK: +#ifdef AP_CONTROL_CLK + gfspi_ioctl_clk_enable(gf_dev); +#endif + break; + + case GF_IOC_DISABLE_SPI_CLK: +#ifdef AP_CONTROL_CLK + gfspi_ioctl_clk_disable(gf_dev); +#endif + break; + + case GF_IOC_ENABLE_POWER: + pr_debug("%s GF_IOC_ENABLE_POWER\n", __func__); + + if (gf_dev->device_available == 1) { + pr_debug("Sensor has already powered-on.\n"); + } else { + gf_power_on(gf_dev); + } + + gf_dev->device_available = 1; + break; + + case GF_IOC_DISABLE_POWER: + pr_debug("%s GF_IOC_DISABLE_POWER\n", __func__); + + if (gf_dev->device_available == 0) { + pr_debug("Sensor has already powered-off.\n"); + } else { + gf_power_off(gf_dev); + } + + gf_dev->device_available = 0; + break; + + case GF_IOC_ENTER_SLEEP_MODE: + pr_debug("%s GF_IOC_ENTER_SLEEP_MODE\n", __func__); + break; + + case GF_IOC_GET_FW_INFO: + pr_debug("%s GF_IOC_GET_FW_INFO\n", __func__); + break; + + case GF_IOC_REMOVE: + pr_debug("%s GF_IOC_REMOVE\n", __func__); + break; + + case GF_IOC_CHIP_INFO: + pr_debug("%s GF_IOC_CHIP_INFO\n", __func__); + + if (copy_from_user(&info, (struct gf_ioc_chip_info *)arg, + sizeof(struct gf_ioc_chip_info))) { + retval = -EFAULT; + break; + } + + pr_debug("vendor_id : 0x%x\n", info.vendor_id); + pr_debug("mode : 0x%x\n", info.mode); + pr_debug("operation: 0x%x\n", info.operation); + break; + + default: + pr_warn("unsupport cmd:0x%x\n", cmd); + break; + } + + return retval; +} + +#ifdef CONFIG_COMPAT +static long gf_compat_ioctl(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return gf_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif /*CONFIG_COMPAT*/ + +#ifndef GOODIX_DRM_INTERFACE_WA +static void notification_work(struct work_struct *work) +{ + pr_debug("%s unblank\n", __func__); + dsi_bridge_interface_enable(FP_UNLOCK_REJECTION_TIMEOUT); +} +#endif + +static irqreturn_t gf_irq(int irq, void *handle) +{ + struct gf_dev *gf_dev = &gf; +#if defined(GF_NETLINK_ENABLE) + char temp[4] = { 0x0 }; + uint32_t key_input = 0; + temp[0] = GF_NET_EVENT_IRQ; + pr_debug("%s enter\n", __func__); + __pm_wakeup_event(&fp_wakelock, WAKELOCK_HOLD_TIME); + sendnlmsg(temp); + + if ((gf_dev->wait_finger_down == true) && (gf_dev->device_available == 1) && + (gf_dev->fb_black == 1)) { + key_input = KEY_RIGHT; + input_report_key(gf_dev->input, key_input, 1); + input_sync(gf_dev->input); + input_report_key(gf_dev->input, key_input, 0); + input_sync(gf_dev->input); + gf_dev->wait_finger_down = false; + schedule_work(&gf_dev->work); + } + +#elif defined (GF_FASYNC) + struct gf_dev *gf_dev = &gf; + + if (gf_dev->async) { + kill_fasync(&gf_dev->async, SIGIO, POLL_IN); + } + +#endif + return IRQ_HANDLED; +} + +static int gf_open(struct inode *inode, struct file *filp) +{ + struct gf_dev *gf_dev; + int status = -ENXIO; + int rc = 0; + int err = 0; + mutex_lock(&device_list_lock); + list_for_each_entry(gf_dev, &device_list, device_entry) { + if (gf_dev->devt == inode->i_rdev) { + pr_debug("Found\n"); + status = 0; + break; + } + } +#ifdef CONFIG_FINGERPRINT_FP_VREG_CONTROL + pr_info("Try to enable fp_vdd_vreg\n"); + gf_dev->vreg = regulator_get(&gf_dev->spi->dev, "fp_vdd_vreg"); + + if (gf_dev->vreg == NULL) { + dev_err(&gf_dev->spi->dev, "fp_vdd_vreg regulator get failed!\n"); + mutex_unlock(&device_list_lock); + return -EPERM; + } + + if (regulator_is_enabled(gf_dev->vreg)) { + pr_info("fp_vdd_vreg is already enabled!\n"); + } else { + rc = regulator_enable(gf_dev->vreg); + + if (rc) { + dev_err(&gf_dev->spi->dev, "error enabling fp_vdd_vreg!\n"); + regulator_put(gf_dev->vreg); + gf_dev->vreg = NULL; + mutex_unlock(&device_list_lock); + return -EPERM; + } + } + + pr_info("fp_vdd_vreg is enabled!\n"); +#endif + + if (status == 0) { + rc = gpio_request(gf_dev->reset_gpio, "goodix_reset"); + + if (rc) { + dev_err(&gf_dev->spi->dev, "Failed to request RESET GPIO. rc = %d\n", rc); + mutex_unlock(&device_list_lock); + err = -EPERM; + goto open_error1; + } + + gpio_direction_output(gf_dev->reset_gpio, 0); + rc = gpio_request(gf_dev->irq_gpio, "goodix_irq"); + + if (rc) { + dev_err(&gf_dev->spi->dev, "Failed to request IRQ GPIO. rc = %d\n", rc); + mutex_unlock(&device_list_lock); + err = -EPERM; + goto open_error2; + } + + gpio_direction_input(gf_dev->irq_gpio); + rc = request_threaded_irq(gf_dev->irq, NULL, gf_irq, + IRQF_TRIGGER_RISING | IRQF_ONESHOT, + "gf", gf_dev); + + if (!rc) { + enable_irq_wake(gf_dev->irq); + gf_dev->irq_enabled = 1; + gf_disable_irq(gf_dev); + } else { + err = -EPERM; + goto open_error3; + } + + gf_dev->users++; + filp->private_data = gf_dev; + nonseekable_open(inode, filp); + pr_debug("Succeed to open device. irq = %d\n", gf_dev->irq); + } else { + pr_debug("No device for minor %d\n", iminor(inode)); + } + + mutex_unlock(&device_list_lock); + return status; +open_error3: + gpio_free(gf_dev->irq_gpio); +open_error2: + gpio_free(gf_dev->reset_gpio); +open_error1: + return err; +} + +#ifdef GF_FASYNC +static int gf_fasync(int fd, struct file *filp, int mode) +{ + struct gf_dev *gf_dev = filp->private_data; + int ret; + ret = fasync_helper(fd, filp, mode, &gf_dev->async); + pr_debug("ret = %d\n", ret); + return ret; +} +#endif + +static int gf_release(struct inode *inode, struct file *filp) +{ + struct gf_dev *gf_dev; + int status = 0; + pr_debug("%s\n", __func__); + mutex_lock(&device_list_lock); + gf_dev = filp->private_data; + filp->private_data = NULL; + /* + *Disable fp_vdd_vreg regulator + */ +#ifdef CONFIG_FINGERPRINT_FP_VREG_CONTROL + pr_info("disable fp_vdd_vreg!\n"); + + if (regulator_is_enabled(gf_dev->vreg)) { + regulator_disable(gf_dev->vreg); + regulator_put(gf_dev->vreg); + gf_dev->vreg = NULL; + } + +#endif + gf_dev->users --; + + if (!gf_dev->users) { + pr_debug("disble_irq. irq = %d\n", gf_dev->irq); + gf_disable_irq(gf_dev); + /*power off the sensor*/ + gf_dev->device_available = 0; + free_irq(gf_dev->irq, gf_dev); + gpio_free(gf_dev->irq_gpio); + gpio_free(gf_dev->reset_gpio); + gf_power_off(gf_dev); + } + + mutex_unlock(&device_list_lock); + return status; +} + +static const struct file_operations gf_fops = { + .owner = THIS_MODULE, + /* REVISIT switch to aio primitives, so that userspace + * gets more complete API coverage. It'll simplify things + * too, except for the locking. + */ + .unlocked_ioctl = gf_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gf_compat_ioctl, +#endif /*CONFIG_COMPAT*/ + .open = gf_open, + .release = gf_release, +#ifdef GF_FASYNC + .fasync = gf_fasync, +#endif +}; + + +#ifndef GOODIX_DRM_INTERFACE_WA +static int goodix_fb_state_chg_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct gf_dev *gf_dev; + struct fb_event *evdata = data; + unsigned int blank; + char temp[4] = { 0x0 }; + + if (val != DRM_EVENT_BLANK) { + return 0; + } + + pr_debug("[info] %s go to the goodix_fb_state_chg_callback value = %d\n", + __func__, (int)val); + gf_dev = container_of(nb, struct gf_dev, notifier); + + if (evdata && evdata->data && val == DRM_EVENT_BLANK && gf_dev) { + blank = *(int *)(evdata->data); + + switch (blank) { + case MSM_DRM_BLANK_POWERDOWN: + if (gf_dev->device_available == 1) { + gf_dev->fb_black = 1; + gf_dev->wait_finger_down = true; +#if defined(GF_NETLINK_ENABLE) + temp[0] = GF_NET_EVENT_FB_BLACK; + sendnlmsg(temp); +#elif defined (GF_FASYNC) + + if (gf_dev->async) { + kill_fasync(&gf_dev->async, SIGIO, POLL_IN); + } + +#endif + } + + break; + + case MSM_DRM_BLANK_UNBLANK: + if (gf_dev->device_available == 1) { + gf_dev->fb_black = 0; +#if defined(GF_NETLINK_ENABLE) + temp[0] = GF_NET_EVENT_FB_UNBLACK; + sendnlmsg(temp); +#elif defined (GF_FASYNC) + + if (gf_dev->async) { + kill_fasync(&gf_dev->async, SIGIO, POLL_IN); + } + +#endif + } + + break; + + default: + pr_debug("%s defalut\n", __func__); + break; + } + } + + return NOTIFY_OK; +} + +static struct notifier_block goodix_noti_block = { + .notifier_call = goodix_fb_state_chg_callback, +}; +#endif + +static struct class *gf_class; +#if defined(USE_SPI_BUS) +static int gf_probe(struct spi_device *spi) +#elif defined(USE_PLATFORM_BUS) +static int gf_probe(struct platform_device *pdev) +#endif +{ + struct gf_dev *gf_dev = &gf; + int status = -EINVAL; + unsigned long minor; + int i; + /* Initialize the driver data */ + INIT_LIST_HEAD(&gf_dev->device_entry); +#if defined(USE_SPI_BUS) + gf_dev->spi = spi; +#elif defined(USE_PLATFORM_BUS) + gf_dev->spi = pdev; +#endif + gf_dev->irq_gpio = -EINVAL; + gf_dev->reset_gpio = -EINVAL; + gf_dev->pwr_gpio = -EINVAL; + gf_dev->device_available = 0; + gf_dev->fb_black = 0; + gf_dev->wait_finger_down = false; +#ifndef GOODIX_DRM_INTERFACE_WA + INIT_WORK(&gf_dev->work, notification_work); +#endif + + if (gf_parse_dts(gf_dev)) { + goto error_hw; + } + + /* If we can allocate a minor number, hook up this device. + * Reusing minors is fine so long as udev or mdev is working. + */ + mutex_lock(&device_list_lock); + minor = find_first_zero_bit(minors, N_SPI_MINORS); + + if (minor < N_SPI_MINORS) { + struct device *dev; + gf_dev->devt = MKDEV(SPIDEV_MAJOR, minor); + dev = device_create(gf_class, &gf_dev->spi->dev, gf_dev->devt, + gf_dev, GF_DEV_NAME); + status = IS_ERR(dev) ? PTR_ERR(dev) : 0; + } else { + dev_dbg(&gf_dev->spi->dev, "no minor number available!\n"); + status = -ENODEV; + mutex_unlock(&device_list_lock); + goto error_hw; + } + + if (status == 0) { + set_bit(minor, minors); + list_add(&gf_dev->device_entry, &device_list); + } else { + gf_dev->devt = 0; + } + + mutex_unlock(&device_list_lock); + + if (status == 0) { + /*input device subsystem */ + gf_dev->input = input_allocate_device(); + + if (gf_dev->input == NULL) { + pr_err("%s, failed to allocate input device\n", __func__); + status = -ENOMEM; + goto error_dev; + } + + for (i = 0; i < ARRAY_SIZE(maps); i++) { + input_set_capability(gf_dev->input, maps[i].type, maps[i].code); + } + + gf_dev->input->name = GF_INPUT_NAME; + status = input_register_device(gf_dev->input); + + if (status) { + pr_err("failed to register input device\n"); + goto error_input; + } + } + +#ifdef AP_CONTROL_CLK + pr_debug("Get the clk resource.\n"); + + /* Enable spi clock */ + if (gfspi_ioctl_clk_init(gf_dev)) { + goto gfspi_probe_clk_init_failed; + } + + if (gfspi_ioctl_clk_enable(gf_dev)) { + goto gfspi_probe_clk_enable_failed; + } + + spi_clock_set(gf_dev, 1000000); +#endif +#ifndef GOODIX_DRM_INTERFACE_WA + gf_dev->notifier = goodix_noti_block; + msm_drm_register_client(&gf_dev->notifier); +#endif + gf_dev->irq = gf_irq_num(gf_dev); + wakeup_source_init(&fp_wakelock, "fp_wakelock"); + pr_debug("version V%d.%d.%02d\n", VER_MAJOR, VER_MINOR, PATCH_LEVEL); + return status; +#ifdef AP_CONTROL_CLK +gfspi_probe_clk_enable_failed: + gfspi_ioctl_clk_uninit(gf_dev); +gfspi_probe_clk_init_failed: +#endif + input_unregister_device(gf_dev->input); +error_input: + + if (gf_dev->input != NULL) { + input_free_device(gf_dev->input); + } + +error_dev: + + if (gf_dev->devt != 0) { + pr_debug("Err: status = %d\n", status); + mutex_lock(&device_list_lock); + list_del(&gf_dev->device_entry); + device_destroy(gf_class, gf_dev->devt); + clear_bit(MINOR(gf_dev->devt), minors); + mutex_unlock(&device_list_lock); + } + +error_hw: + gf_cleanup(gf_dev); + gf_dev->device_available = 0; + return status; +} + +#if defined(USE_SPI_BUS) +static int gf_remove(struct spi_device *spi) +#elif defined(USE_PLATFORM_BUS) +static int gf_remove(struct platform_device *pdev) +#endif +{ + struct gf_dev *gf_dev = &gf; + wakeup_source_trash(&fp_wakelock); + + /* make sure ops on existing fds can abort cleanly */ + if (gf_dev->irq) { + free_irq(gf_dev->irq, gf_dev); + } + + if (gf_dev->input != NULL) { + input_unregister_device(gf_dev->input); + } + + input_free_device(gf_dev->input); + /* prevent new opens */ + mutex_lock(&device_list_lock); + list_del(&gf_dev->device_entry); + device_destroy(gf_class, gf_dev->devt); + clear_bit(MINOR(gf_dev->devt), minors); + + if (gf_dev->users == 0) { + gf_cleanup(gf_dev); + } + +#ifndef GOODIX_DRM_INTERFACE_WA + msm_drm_unregister_client(&gf_dev->notifier); +#endif + mutex_unlock(&device_list_lock); + return 0; +} + +static struct of_device_id gx_match_table[] = { + { .compatible = GF_SPIDEV_NAME }, + {}, +}; + +#if defined(USE_SPI_BUS) +static struct spi_driver gf_driver = { +#elif defined(USE_PLATFORM_BUS) +static struct platform_driver gf_driver = { +#endif + .driver = { + .name = GF_DEV_NAME, + .owner = THIS_MODULE, + .of_match_table = gx_match_table, + }, + .probe = gf_probe, + .remove = gf_remove, +}; + +static int __init gf_init(void) +{ + int status; + /* Claim our 256 reserved device numbers. Then register a class + * that will key udev/mdev to add/remove /dev nodes. Last, register + * the driver which manages those device numbers. + */ + BUILD_BUG_ON(N_SPI_MINORS > 256); + status = register_chrdev(SPIDEV_MAJOR, CHRD_DRIVER_NAME, &gf_fops); + + if (status < 0) { + pr_warn("Failed to register char device!\n"); + return status; + } + + SPIDEV_MAJOR = status; + gf_class = class_create(THIS_MODULE, CLASS_NAME); + + if (IS_ERR(gf_class)) { + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name); + pr_warn("Failed to create class.\n"); + return PTR_ERR(gf_class); + } + +#if defined(USE_PLATFORM_BUS) + status = platform_driver_register(&gf_driver); +#elif defined(USE_SPI_BUS) + status = spi_register_driver(&gf_driver); +#endif + + if (status < 0) { + class_destroy(gf_class); + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name); + pr_warn("Failed to register SPI driver.\n"); + } + +#ifdef GF_NETLINK_ENABLE + netlink_init(); +#endif + pr_debug("status = 0x%x\n", status); + return 0; +} +module_init(gf_init); + +static void __exit gf_exit(void) +{ +#ifdef GF_NETLINK_ENABLE + netlink_exit(); +#endif +#if defined(USE_PLATFORM_BUS) + platform_driver_unregister(&gf_driver); +#elif defined(USE_SPI_BUS) + spi_unregister_driver(&gf_driver); +#endif + class_destroy(gf_class); + unregister_chrdev(SPIDEV_MAJOR, gf_driver.driver.name); +} +module_exit(gf_exit); + +MODULE_AUTHOR("Jiangtao Yi, "); +MODULE_AUTHOR("Jandy Gou, "); +MODULE_DESCRIPTION("goodix fingerprint sensor device driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/input/fingerprint/goodix_ta/gf_spi.h b/drivers/input/fingerprint/goodix_ta/gf_spi.h new file mode 100644 index 000000000000..26fe78ea2fbd --- /dev/null +++ b/drivers/input/fingerprint/goodix_ta/gf_spi.h @@ -0,0 +1,160 @@ +/* + * driver definition for sensor driver + * + * Coypright (c) 2017 Goodix + */ +#ifndef __GF_SPI_H +#define __GF_SPI_H + +#include +#include +/**********************************************************/ +enum FP_MODE { + GF_IMAGE_MODE = 0, + GF_KEY_MODE, + GF_SLEEP_MODE, + GF_FF_MODE, + GF_DEBUG_MODE = 0x56 +}; + +#define SUPPORT_NAV_EVENT + +#if defined(SUPPORT_NAV_EVENT) +#define GF_NAV_INPUT_UP KEY_UP +#define GF_NAV_INPUT_DOWN KEY_DOWN +#define GF_NAV_INPUT_LEFT KEY_LEFT +#define GF_NAV_INPUT_RIGHT KEY_RIGHT +#define GF_NAV_INPUT_CLICK KEY_VOLUMEDOWN +#define GF_NAV_INPUT_DOUBLE_CLICK KEY_VOLUMEUP +#define GF_NAV_INPUT_LONG_PRESS KEY_SEARCH +#define GF_NAV_INPUT_HEAVY KEY_CHAT +#endif + +#define GF_KEY_INPUT_HOME KEY_HOME +#define GF_KEY_INPUT_MENU KEY_MENU +#define GF_KEY_INPUT_BACK KEY_BACK +#define GF_KEY_INPUT_POWER KEY_POWER +#define GF_KEY_INPUT_CAMERA KEY_CAMERA + +#if defined(SUPPORT_NAV_EVENT) +typedef enum gf_nav_event { + GF_NAV_NONE = 0, + GF_NAV_FINGER_UP, + GF_NAV_FINGER_DOWN, + GF_NAV_UP, + GF_NAV_DOWN, + GF_NAV_LEFT, + GF_NAV_RIGHT, + GF_NAV_CLICK, + GF_NAV_HEAVY, + GF_NAV_LONG_PRESS, + GF_NAV_DOUBLE_CLICK, +} gf_nav_event_t; +#endif + +typedef enum gf_key_event { + GF_KEY_NONE = 0, + GF_KEY_HOME, + GF_KEY_POWER, + GF_KEY_MENU, + GF_KEY_BACK, + GF_KEY_CAMERA, +} gf_key_event_t; + +struct gf_key { + enum gf_key_event key; + uint32_t value; /* key down = 1, key up = 0 */ +}; + +struct gf_key_map { + unsigned int type; + unsigned int code; +}; + +struct gf_ioc_chip_info { + unsigned char vendor_id; + unsigned char mode; + unsigned char operation; + unsigned char reserved[5]; +}; + +#define GF_IOC_MAGIC 'g' /*define magic number*/ +#define GF_IOC_INIT _IOR(GF_IOC_MAGIC, 0, uint8_t) +#define GF_IOC_EXIT _IO(GF_IOC_MAGIC, 1) +#define GF_IOC_RESET _IO(GF_IOC_MAGIC, 2) +#define GF_IOC_ENABLE_IRQ _IO(GF_IOC_MAGIC, 3) +#define GF_IOC_DISABLE_IRQ _IO(GF_IOC_MAGIC, 4) +#define GF_IOC_ENABLE_SPI_CLK _IOW(GF_IOC_MAGIC, 5, uint32_t) +#define GF_IOC_DISABLE_SPI_CLK _IO(GF_IOC_MAGIC, 6) +#define GF_IOC_ENABLE_POWER _IO(GF_IOC_MAGIC, 7) +#define GF_IOC_DISABLE_POWER _IO(GF_IOC_MAGIC, 8) +#define GF_IOC_INPUT_KEY_EVENT _IOW(GF_IOC_MAGIC, 9, struct gf_key) +#define GF_IOC_ENTER_SLEEP_MODE _IO(GF_IOC_MAGIC, 10) +#define GF_IOC_GET_FW_INFO _IOR(GF_IOC_MAGIC, 11, uint8_t) +#define GF_IOC_REMOVE _IO(GF_IOC_MAGIC, 12) +#define GF_IOC_CHIP_INFO _IOW(GF_IOC_MAGIC, 13, struct gf_ioc_chip_info) + +#if defined(SUPPORT_NAV_EVENT) +#define GF_IOC_NAV_EVENT _IOW(GF_IOC_MAGIC, 14, gf_nav_event_t) +#define GF_IOC_MAXNR 15 /* THIS MACRO IS NOT USED NOW... */ +#else +#define GF_IOC_MAXNR 14 /* THIS MACRO IS NOT USED NOW... */ +#endif + +/*#define AP_CONTROL_CLK 1*/ +#define USE_PLATFORM_BUS 1 +/*#define USE_SPI_BUS 1*/ +/*#define GF_FASYNC 1*//*If support fasync mechanism.*/ +#define GF_PW_CTL 1 +#define GF_NETLINK_ENABLE 1 +#define GF_NET_EVENT_IRQ 1 +#define GF_NET_EVENT_FB_BLACK 2 +#define GF_NET_EVENT_FB_UNBLACK 3 +#define NETLINK_TEST 25 + +struct gf_dev { + dev_t devt; + struct list_head device_entry; +#if defined(USE_SPI_BUS) + struct spi_device *spi; +#elif defined(USE_PLATFORM_BUS) + struct platform_device *spi; +#endif + struct clk *core_clk; + struct clk *iface_clk; + + struct input_dev *input; + /* buffer is NULL unless this device is open (users > 0) */ + unsigned users; + signed irq_gpio; + signed reset_gpio; + signed pwr_gpio; + int irq; + int irq_enabled; + int clk_enabled; +#ifdef GF_FASYNC + struct fasync_struct *async; +#endif + struct notifier_block notifier; + char device_available; + char fb_black; + char wait_finger_down; + struct work_struct work; +#ifdef CONFIG_FINGERPRINT_FP_VREG_CONTROL + struct regulator *vreg; +#endif +}; + +int gf_parse_dts(struct gf_dev *gf_dev); +void gf_cleanup(struct gf_dev *gf_dev); + +int gf_power_on(struct gf_dev *gf_dev); +int gf_power_off(struct gf_dev *gf_dev); + +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms); +int gf_irq_num(struct gf_dev *gf_dev); + +void sendnlmsg(char *message); +int netlink_init(void); +void netlink_exit(void); +#endif /*__GF_SPI_H*/ diff --git a/drivers/input/fingerprint/goodix_ta/netlink.c b/drivers/input/fingerprint/goodix_ta/netlink.c new file mode 100644 index 000000000000..613a9889ef87 --- /dev/null +++ b/drivers/input/fingerprint/goodix_ta/netlink.c @@ -0,0 +1,100 @@ +/* + * netlink interface + * + * Copyright (c) 2017 Goodix + * Copyright (C) 2019 XiaoMi, Inc. + */ +#include +#include +#include +#include +#include +#include +#include + +#define NETLINK_TEST 25 +#define MAX_MSGSIZE 32 +int stringlength(char *s); +void sendnlmsg(char *message); +static int pid = -1; +struct sock *nl_sk = NULL; + +void sendnlmsg(char *message) +{ + struct sk_buff *skb_1; + struct nlmsghdr *nlh; + int len = NLMSG_SPACE(MAX_MSGSIZE); + int slen = 0; + int ret = 0; + + if (!message || !nl_sk || !pid) { + return; + } + + skb_1 = alloc_skb(len, GFP_KERNEL); + + if (!skb_1) { + pr_err("alloc_skb error\n"); + return; + } + + slen = strlen(message); + nlh = nlmsg_put(skb_1, 0, 0, 0, MAX_MSGSIZE, 0); + NETLINK_CB(skb_1).portid = 0; + NETLINK_CB(skb_1).dst_group = 0; + message[slen] = '\0'; + memcpy(NLMSG_DATA(nlh), message, slen + 1); + ret = netlink_unicast(nl_sk, skb_1, pid, MSG_DONTWAIT); + + if (!ret) { + /*kfree_skb(skb_1);*/ + pr_err("send msg from kernel to usespace failed ret 0x%x\n", ret); + } +} + + +void nl_data_ready(struct sk_buff *__skb) +{ + struct sk_buff *skb; + struct nlmsghdr *nlh; + char str[100]; + skb = skb_get(__skb); + + if (skb->len >= NLMSG_SPACE(0)) { + nlh = nlmsg_hdr(skb); + memcpy(str, NLMSG_DATA(nlh), sizeof(str)); + pid = nlh->nlmsg_pid; + kfree_skb(skb); + } +} + + +int netlink_init(void) +{ + struct netlink_kernel_cfg netlink_cfg; + memset(&netlink_cfg, 0, sizeof(struct netlink_kernel_cfg)); + netlink_cfg.groups = 0; + netlink_cfg.flags = 0; + netlink_cfg.input = nl_data_ready; + netlink_cfg.cb_mutex = NULL; + nl_sk = netlink_kernel_create(&init_net, NETLINK_TEST, + &netlink_cfg); + + if (!nl_sk) { + pr_err("create netlink socket error\n"); + return 1; + } + + return 0; +} + +void netlink_exit(void) +{ + if (nl_sk != NULL) { + netlink_kernel_release(nl_sk); + nl_sk = NULL; + } + + pr_info("self module exited\n"); +} + diff --git a/drivers/input/fingerprint/goodix_ta/platform.c b/drivers/input/fingerprint/goodix_ta/platform.c new file mode 100644 index 000000000000..553750eb3d94 --- /dev/null +++ b/drivers/input/fingerprint/goodix_ta/platform.c @@ -0,0 +1,150 @@ +/* + * platform indepent driver interface + * + * Coypritht (c) 2017 Goodix + */ +#define DEBUG +#define pr_fmt(fmt) "gf_platform: " fmt + +#include +#include +#include +#include +#include +#include +#include + +#include "gf_spi.h" + +#if defined(USE_SPI_BUS) +#include +#include +#elif defined(USE_PLATFORM_BUS) +#include +#endif + +int gf_parse_dts(struct gf_dev *gf_dev) +{ +#ifdef GF_PW_CTL + int rc = 0; + /*get pwr resource*/ + gf_dev->pwr_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, "fp-gpio-pwr", + 0); + + if (!gpio_is_valid(gf_dev->pwr_gpio)) { + pr_info("PWR GPIO is invalid.\n"); + return -1; + } + + rc = gpio_request(gf_dev->pwr_gpio, "goodix_pwr"); + + if (rc) { + dev_err(&gf_dev->spi->dev, "Failed to request PWR GPIO. rc = %d\n", rc); + return -1; + } + +#endif + /*get reset resource*/ + gf_dev->reset_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, + "goodix,gpio-reset", 0); + + if (!gpio_is_valid(gf_dev->reset_gpio)) { + pr_info("RESET GPIO is invalid.\n"); + return -EPERM; + } + + /*get irq resourece*/ + gf_dev->irq_gpio = of_get_named_gpio(gf_dev->spi->dev.of_node, + "goodix,gpio-irq", 0); + pr_info("gf::irq_gpio:%d\n", gf_dev->irq_gpio); + + if (!gpio_is_valid(gf_dev->irq_gpio)) { + pr_info("IRQ GPIO is invalid.\n"); + return -EPERM; + } + + return 0; +} + +void gf_cleanup(struct gf_dev *gf_dev) +{ + pr_info("[info] %s\n", __func__); + + if (gpio_is_valid(gf_dev->irq_gpio)) { + gpio_free(gf_dev->irq_gpio); + pr_info("remove irq_gpio success\n"); + } + + if (gpio_is_valid(gf_dev->reset_gpio)) { + gpio_free(gf_dev->reset_gpio); + pr_info("remove reset_gpio success\n"); + } + +#ifdef GF_PW_CTL + + if (gpio_is_valid(gf_dev->pwr_gpio)) { + gpio_free(gf_dev->pwr_gpio); + pr_info("remove pwr_gpio success\n"); + } + +#endif +} + +int gf_power_on(struct gf_dev *gf_dev) +{ + int rc = 0; +#ifdef GF_PW_CTL + + if (gpio_is_valid(gf_dev->pwr_gpio)) { + rc = gpio_direction_output(gf_dev->pwr_gpio, 1); + pr_info("---- power on result: %d----\n", rc); + } else { + pr_info("%s: gpio_is_invalid\n", __func__); + } + +#endif + msleep(10); + return rc; +} + +int gf_power_off(struct gf_dev *gf_dev) +{ + int rc = 0; +#ifdef GF_PW_CTL + + if (gpio_is_valid(gf_dev->pwr_gpio)) { + rc = gpio_direction_output(gf_dev->pwr_gpio, 0); + pr_info("---- power off result: %d----\n", rc); + } else { + pr_info("%s: gpio_is_invalid\n", __func__); + } + +#endif + return rc; +} + +int gf_hw_reset(struct gf_dev *gf_dev, unsigned int delay_ms) +{ + if (gf_dev == NULL) { + pr_info("Input buff is NULL.\n"); + return -EPERM; + } + + gpio_direction_output(gf_dev->reset_gpio, 0); + mdelay(3); + gpio_set_value(gf_dev->reset_gpio, 1); + mdelay(delay_ms); + pr_info("%s\n", __func__); + return 0; +} + +int gf_irq_num(struct gf_dev *gf_dev) +{ + if (gf_dev == NULL) { + pr_info("Input buff is NULL.\n"); + return -EPERM; + } else { + return gpio_to_irq(gf_dev->irq_gpio); + } +} + diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index e9f0ebf3267a..1b37539eafb9 100644 --- a/drivers/input/keyboard/gpio_keys.c +++ b/drivers/input/keyboard/gpio_keys.c @@ -385,6 +385,19 @@ static void gpio_keys_gpio_work_func(struct work_struct *work) struct gpio_button_data *bdata = container_of(work, struct gpio_button_data, work.work); + if (bdata->button->level_trigger) { + unsigned int trigger = + irq_get_trigger_type(bdata->irq) & ~IRQF_TRIGGER_MASK; + int state = gpiod_get_value_cansleep(bdata->gpiod); + if (state) + trigger |= IRQF_TRIGGER_HIGH; + else + trigger |= IRQF_TRIGGER_LOW; + + irq_set_irq_type(bdata->irq, trigger); + enable_irq(bdata->irq); + printk("storm state:%d, trigger:%x\n", state, trigger); + } gpio_keys_gpio_report_event(bdata); if (bdata->button->wakeup) @@ -397,12 +410,16 @@ static irqreturn_t gpio_keys_gpio_isr(int irq, void *dev_id) BUG_ON(irq != bdata->irq); + if (bdata->button->level_trigger) + disable_irq_nosync(bdata->irq); + if (bdata->button->wakeup) { const struct gpio_keys_button *button = bdata->button; pm_stay_awake(bdata->input->dev.parent); if (bdata->suspended && - (button->type == 0 || button->type == EV_KEY)) { + (button->type == 0 || button->type == EV_KEY) && + (button->code != KEY_AI)) { /* * Simulate wakeup key press in case the key has * already released by the time we got interrupt @@ -566,7 +583,12 @@ static int gpio_keys_setup_key(struct platform_device *pdev, INIT_DELAYED_WORK(&bdata->work, gpio_keys_gpio_work_func); isr = gpio_keys_gpio_isr; - irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + if (bdata->button->level_trigger) { + irqflags = gpiod_is_active_low(bdata->gpiod) ? + IRQF_TRIGGER_LOW : IRQF_TRIGGER_HIGH; + } else { + irqflags = IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING; + } } else { if (!button->irq) { @@ -722,6 +744,9 @@ gpio_keys_get_devtree_pdata(struct device *dev) button->can_disable = fwnode_property_read_bool(child, "linux,can-disable"); + button->level_trigger = + fwnode_property_read_bool(child, "gpio-key,level-trigger"); + if (fwnode_property_read_u32(child, "debounce-interval", &button->debounce_interval)) button->debounce_interval = 5; diff --git a/drivers/input/misc/qti-haptics.c b/drivers/input/misc/qti-haptics.c index 348401da093e..47899aa8f16d 100644 --- a/drivers/input/misc/qti-haptics.c +++ b/drivers/input/misc/qti-haptics.c @@ -1119,7 +1119,7 @@ static int qti_haptics_hw_init(struct qti_hap_chip *chip) addr = REG_HAP_AUTO_RES_CFG; mask = HAP_AUTO_RES_MODE_BIT | HAP_CAL_EOP_EN_BIT | HAP_CAL_PERIOD_MASK; val = config->lra_auto_res_mode << HAP_AUTO_RES_MODE_SHIFT; - val |= HAP_CAL_EOP_EN_BIT | HAP_CAL_OPT3_EVERY_8_PERIOD; + val |= HAP_CAL_EOP_EN_BIT; rc = qti_haptics_masked_write(chip, addr, mask, val); if (rc < 0) { dev_err(chip->dev, "set AUTO_RES_CFG failed, rc=%d\n", rc); diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig index a238a102bdf0..3b08db4c513a 100644 --- a/drivers/input/touchscreen/Kconfig +++ b/drivers/input/touchscreen/Kconfig @@ -11,6 +11,14 @@ menuconfig INPUT_TOUCHSCREEN if INPUT_TOUCHSCREEN +source "drivers/input/touchscreen/fts_521/Kconfig" + +config SECURE_TOUCH + bool "Secure Touch" + +config I2C_BY_DMA + bool "I2C BY DMA" + config TOUCHSCREEN_PROPERTIES def_tristate INPUT depends on INPUT diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile index 8c54ef46cf2c..63cb0b4bffdc 100644 --- a/drivers/input/touchscreen/Makefile +++ b/drivers/input/touchscreen/Makefile @@ -108,3 +108,4 @@ obj-$(CONFIG_TOUCHSCREEN_ROHM_BU21023) += rohm_bu21023.o obj-$(CONFIG_TOUCHSCREEN_ST) += st/ obj-$(CONFIG_TOUCHSCREEN_HIMAX_CHIPSET) += hxchipset/ obj-$(CONFIG_TOUCHSCREEN_SYNAPTICS_TCM) += synaptics_tcm/ +obj-$(CONFIG_TOUCHSCREEN_ST_FTS_V521) += fts_521/ diff --git a/drivers/input/touchscreen/fts_521/Kconfig b/drivers/input/touchscreen/fts_521/Kconfig new file mode 100644 index 000000000000..3f2e20abb7f8 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/Kconfig @@ -0,0 +1,25 @@ +config TOUCHSCREEN_ST_FTS_V521 + tristate "ST FTS V521 I2C Touchscreen" + depends on I2C + help + Say Y here if you have ST FTS series I2C touchscreen. + + If unsure, say N. + + To compile this driver as a module, choose M here: the + +config FTS_FOD_AREA_REPORT + tristate "FTS FOD area report" + depends on TOUCHSCREEN_ST_FTS_V521 + help + Say Y here to enable fod area report functionality. + + If unsure, say N. + +config TOUCHSCREEN_ST_DEBUG_FS + tristate "St core driver module" + depends on TOUCHSCREEN_ST_FTS_V521 + help + Say Y here to enable touch debugfs functionality. + + If unsure, say N. \ No newline at end of file diff --git a/drivers/input/touchscreen/fts_521/Makefile b/drivers/input/touchscreen/fts_521/Makefile new file mode 100644 index 000000000000..cf21f2190fcc --- /dev/null +++ b/drivers/input/touchscreen/fts_521/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for the touchscreen drivers. +# + +obj-$(CONFIG_TOUCHSCREEN_ST_FTS_V521) += fts.o fts_proc.o fts_lib/ + diff --git a/drivers/input/touchscreen/fts_521/fts.c b/drivers/input/touchscreen/fts_521/fts.c new file mode 100644 index 000000000000..1fb3619c54e8 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts.c @@ -0,0 +1,6284 @@ +/* + * fts.c + * + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2016, STMicroelectronics Limited. + * Authors: AMG(Analog Mems Group) + * + * marco.cali@st.com + * + * 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. + * + * THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE + * PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. + * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, + * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE + * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING + * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. + */ + +/*! +* \file fts.c +* \brief It is the main file which contains all the most important functions generally used by a device driver the driver +*/ +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef CONFIG_SECURE_TOUCH +#include +#include +#include +#endif + +#include +#include +#include + +#include +#ifdef CONFIG_DRM +#include +#endif + +#include +#include +#include +#include + +#ifdef KERNEL_ABOVE_2_6_38 +#include +#endif + +#include "fts.h" +#include "fts_lib/ftsCompensation.h" +#include "fts_lib/ftsCore.h" +#include "fts_lib/ftsIO.h" +#include "fts_lib/ftsError.h" +#include "fts_lib/ftsFlash.h" +#include "fts_lib/ftsFrame.h" +#include "fts_lib/ftsGesture.h" +#include "fts_lib/ftsTest.h" +#include "fts_lib/ftsTime.h" +#include "fts_lib/ftsTool.h" + +/** + * Event handler installer helpers + */ +#define event_id(_e) (EVT_ID_##_e>>4) +#define handler_name(_h) fts_##_h##_event_handler + +#define install_handler(_i, _evt, _hnd) \ +do { \ + _i->event_dispatch_table[event_id(_evt)] = handler_name(_hnd); \ +} while (0) + +#ifdef KERNEL_ABOVE_2_6_38 +#define TYPE_B_PROTOCOL +#endif + +#define INPUT_EVENT_START 0 +#define INPUT_EVENT_SENSITIVE_MODE_OFF 0 +#define INPUT_EVENT_SENSITIVE_MODE_ON 1 +#define INPUT_EVENT_STYLUS_MODE_OFF 2 +#define INPUT_EVENT_STYLUS_MODE_ON 3 +#define INPUT_EVENT_WAKUP_MODE_OFF 4 +#define INPUT_EVENT_WAKUP_MODE_ON 5 +#define INPUT_EVENT_COVER_MODE_OFF 6 +#define INPUT_EVENT_COVER_MODE_ON 7 +#define INPUT_EVENT_SLIDE_FOR_VOLUME 8 +#define INPUT_EVENT_DOUBLE_TAP_FOR_VOLUME 9 +#define INPUT_EVENT_SINGLE_TAP_FOR_VOLUME 10 +#define INPUT_EVENT_LONG_SINGLE_TAP_FOR_VOLUME 11 +#define INPUT_EVENT_PALM_OFF 12 +#define INPUT_EVENT_PALM_ON 13 +#define INPUT_EVENT_END 13 + +extern SysInfo systemInfo; +extern TestToDo tests; +#ifdef GESTURE_MODE +extern struct mutex gestureMask_mutex; +#endif + +char tag[8] = "[ FTS ]\0"; +/* buffer which store the input device name assigned by the kernel */ +char fts_ts_phys[64]; +/* buffer used to store the command sent from the MP device file node */ +static u32 typeOfComand[CMD_STR_LEN] = { 0 }; + +/* number of parameter passed through the MP device file node */ +static int numberParameters; +#ifdef USE_ONE_FILE_NODE +static int feature_feasibility = ERROR_OP_NOT_ALLOW; +#endif +#ifdef GESTURE_MODE +static u8 mask[GESTURE_MASK_SIZE + 2]; +extern u16 gesture_coordinates_x[GESTURE_MAX_COORDS_PAIRS_REPORT]; +extern u16 gesture_coordinates_y[GESTURE_MAX_COORDS_PAIRS_REPORT]; +extern int gesture_coords_reported; +extern struct mutex gestureMask_mutex; +#endif +/* store the last update of the key mask published by the IC */ +#ifdef PHONE_KEY +static u8 key_mask; +#endif + +extern spinlock_t fts_int; +struct fts_ts_info *fts_info; + +static int fts_init_sensing(struct fts_ts_info *info); +static int fts_mode_handler(struct fts_ts_info *info, int force); +static int fts_chip_initialization(struct fts_ts_info *info, int init_type); +static const char *fts_get_limit(struct fts_ts_info *info); +static irqreturn_t fts_event_handler(int irq, void *ts_info); + +/** +* Release all the touches in the linux input subsystem +* @param info pointer to fts_ts_info which contains info about the device and its hw setup +*/ +void release_all_touches(struct fts_ts_info *info) +{ + unsigned int type = MT_TOOL_FINGER; + int i; + + for (i = 0; i < TOUCH_ID_MAX; i++) { +#ifdef STYLUS_MODE + if (test_bit(i, &info->stylus_id)) + type = MT_TOOL_PEN; + else + type = MT_TOOL_FINGER; +#endif + info->coor[i][0] = -1; + info->coor[i][1] = -1; + input_mt_slot(info->input_dev, i); + input_mt_report_slot_state(info->input_dev, type, 0); + } + input_sync(info->input_dev); + info->touch_id = 0; + info->touch_skip = 0; + info->fod_id = 0; +#ifdef STYLUS_MODE + info->stylus_id = 0; +#endif +} + +/** + * @defgroup file_nodes Driver File Nodes + * Driver publish a series of file nodes used to provide several utilities to the host and give him access to different API. + * @{ + */ + +/** + * @defgroup device_file_nodes Device File Nodes + * @ingroup file_nodes + * Device File Nodes \n + * There are several file nodes that are associated to the device and which are designed to be used by the host to enable/disable features or trigger some system specific actions \n + * Usually their final path depend on the definition of device tree node of the IC (e.g /sys/devices/soc.0/f9928000.i2c/i2c-6/6-0049) + * @{ + */ +/***************************************** FW UPGGRADE ***************************************************/ + +/** + * File node function to Update firmware from shell \n + * echo path_to_fw X Y > fwupdate perform a fw update \n + * where: \n + * path_to_fw = file name or path of the the FW to burn, if "NULL" the default approach selected in the driver will be used\n + * X = 0/1 to force the FW update whichever fw_version and config_id; 0=perform a fw update only if the fw in the file is newer than the fw in the chip \n + * Y = 0/1 keep the initialization data; 0 = will erase the initialization data from flash, 1 = will keep the initialization data + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent an error code (00000000 no error) \n + * } = end byte + */ +static ssize_t fts_fwupdate_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret, mode[2]; + char path[100]; + struct fts_ts_info *info = dev_get_drvdata(dev); + + /* by default(if not specified by the user) set the force = 0 and keep_cx to 1 */ + mode[0] = 0; + mode[1] = 1; + + /* reading out firmware upgrade parameters */ + sscanf(buf, "%100s %d %d", path, &mode[0], &mode[1]); + logError(1, "%s fts_fwupdate_store: mode = %s \n", tag, path); + + ret = flashProcedure(path, mode[0], mode[1]); + + info->fwupdate_stat = ret; + + if (ret < OK) + logError(1, "%s %s Unable to upgrade firmware! ERROR %08X\n", + tag, __func__, ret); + return count; +} + +static ssize_t fts_fwupdate_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + /*fwupdate_stat: ERROR code Returned by flashProcedure. */ + return snprintf(buf, PAGE_SIZE, "{ %08X }\n", info->fwupdate_stat); +} + +/***************************************** UTILITIES (current fw_ver/conf_id, active mode, file fw_ver/conf_id) ***************************************************/ +/** +* File node to show on terminal external release version in Little Endian (first the less significant byte) \n +* cat appid show on the terminal external release version of the FW running in the IC +*/ +static ssize_t fts_appid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int error; + char temp[100] = { 0x00, }; + + error = snprintf(buf, PAGE_SIZE, "%s\n", + printHex("EXT Release = ", systemInfo.u8_releaseInfo, + EXTERNAL_RELEASE_INFO_SIZE, temp)); + + return error; +} + +/** + * File node to show on terminal the mode that is active on the IC \n + * cat mode_active to show the bitmask which indicate the modes/features which are running on the IC in a specific instant of time + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1 = 1 byte in HEX format which represent the actual running scan mode (@link scan_opt Scan Mode Options @endlink) \n + * X2 = 1 byte in HEX format which represent the bitmask on which is running the actual scan mode \n + * X3X4 = 2 bytes in HEX format which represent a bitmask of the features that are enabled at this moment (@link feat_opt Feature Selection Options @endlink) \n + * } = end byte + * @see fts_mode_handler() + */ +static ssize_t fts_mode_active_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(1, "%s Current mode active = %08X\n", tag, info->mode); + return snprintf(buf, PAGE_SIZE, "{ %08X }\n", info->mode); +} + +/** + * File node to show the fw_ver and config_id of the FW file + * cat fw_file_test show on the kernel log fw_version and config_id of the FW stored in the fw file/header file + */ +static ssize_t fts_fw_test_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + Firmware fw; + int ret; + char temp[100] = { 0x00, }; + struct fts_ts_info *info = dev_get_drvdata(dev); + + fw.data = NULL; + ret = readFwFile(info->board->default_fw_name, &fw, 0); + + if (ret < OK) { + logError(1, "%s Error during reading FW file! ERROR %08X\n", + tag, ret); + } else { + logError(1, "%s %s, size = %d bytes\n", tag, + printHex("EXT Release = ", systemInfo.u8_releaseInfo, + EXTERNAL_RELEASE_INFO_SIZE, temp), + fw.data_size); + } + + kfree(fw.data); + return 0; +} + +/***************************************** FEATURES ***************************************************/ + +/*TODO: edit this function according to the features policy to allow during the screen on/off, following is shown an example but check always with ST for more details*/ +/** + * Check if there is any conflict in enable/disable a particular feature considering the features already enabled and running + * @param info pointer to fts_ts_info which contains info about the device and its hw setup + * @param feature code of the feature that want to be tested + * @return OK if is possible to enable/disable feature, ERROR_OP_NOT_ALLOW in case of any other conflict + */ +int check_feature_feasibility(struct fts_ts_info *info, unsigned int feature) +{ + int res = OK; + + switch (feature) { + case FEAT_SEL_GESTURE: + if (info->cover_enabled == 1) { + res = ERROR_OP_NOT_ALLOW; + logError(1, + "%s %s: Feature not allowed when in Cover mode! ERROR %08X \n", + tag, __func__, res); + /*for example here can be placed a code for disabling the cover mode when gesture is activated */ + } + break; + + case FEAT_SEL_GLOVE: + if (info->gesture_enabled == 1) { + res = ERROR_OP_NOT_ALLOW; + logError(1, + "%s %s: Feature not allowed when Gestures enabled! ERROR %08X \n", + tag, __func__, res); + /*for example here can be placed a code for disabling the gesture mode when cover is activated (that means that cover mode has an higher priority on gesture mode) */ + } + break; + + default: + logError(1, "%s %s: Feature Allowed! \n", tag, __func__); + + } + + return res; + +} + +#ifdef USE_ONE_FILE_NODE +/** + * File node to enable some feature + * echo XX 00/01 > feature_enable to enable/disable XX (possible values @link feat_opt Feature Selection Options @endlink) feature \n + * cat feature_enable to show the result of enabling/disabling process \n + * echo 01/00 > feature_enable; cat feature_enable to perform both actions stated before in just one call \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent an error code (00000000 = no error) \n + * } = end byte + */ +static ssize_t fts_feature_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + char *p = (char *)buf; + unsigned int temp; + int res = OK; + + if ((count - 2 + 1) / 3 != 1) { + logError(1, + "%s fts_feature_enable: Number of parameter wrong! %d > %d \n", + tag, (count - 2 + 1) / 3, 1); + } else { + sscanf(p, "%02X ", &temp); + p += 9; + res = check_feature_feasibility(info, temp); + if (res >= OK) { + switch (temp) { + +#ifdef GESTURE_MODE + case FEAT_SEL_GESTURE: + sscanf(p, "%02X ", &info->gesture_enabled); + logError(1, + "%s fts_feature_enable: Gesture Enabled = %d \n", + tag, info->gesture_enabled); + break; +#endif + +#ifdef GLOVE_MODE + case FEAT_SEL_GLOVE: + sscanf(p, "%02X ", &info->glove_enabled); + logError(1, + "%s fts_feature_enable: Glove Enabled = %d \n", + tag, info->glove_enabled); + + break; +#endif + +#ifdef STYLUS_MODE + case FEAT_SEL_STYLUS: + sscanf(p, "%02X ", &info->stylus_enabled); + logError(1, + "%s fts_feature_enable: Stylus Enabled = %d \n", + tag, info->stylus_enabled); + + break; +#endif + +#ifdef COVER_MODE + case FEAT_SEL_COVER: + sscanf(p, "%02X ", &info->cover_enabled); + logError(1, + "%s fts_feature_enable: Cover Enabled = %d \n", + tag, info->cover_enabled); + + break; +#endif + +#ifdef CHARGER_MODE + case FEAT_SEL_CHARGER: + sscanf(p, "%02X ", &info->charger_enabled); + logError(1, + "%s fts_feature_enable: Charger Enabled = %d \n", + tag, info->charger_enabled); + + break; +#endif + +#ifdef GRIP_MODE + case FEAT_SEL_GRIP: + sscanf(p, "%02X ", &info->grip_enabled); + logError(1, + "%s fts_feature_enable: Grip Enabled = %d \n", + tag, info->grip_enabled); + + break; +#endif + default: + logError(1, + "%s fts_feature_enable: Feature %08X not valid! ERROR %08X\n", + tag, temp, ERROR_OP_NOT_ALLOW); + res = ERROR_OP_NOT_ALLOW; + } + feature_feasibility = res; + } + if (feature_feasibility >= OK) + feature_feasibility = fts_mode_handler(info, 1); + else { + logError(1, + "%s %s: Call echo XX 00/01 > feature_enable with a correct feature value (XX)! ERROR %08X \n", + tag, __func__, res); + } + + } + return count; +} + +static ssize_t fts_feature_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0; + + if (feature_feasibility < OK) { + logError(1, + "%s %s: Call before echo XX 00/01 > feature_enable with a correct feature value (XX)! ERROR %08X \n", + tag, __func__, feature_feasibility); + } + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + index += + snprintf(&all_strbuff[index], 13, "{ %08X }", + feature_feasibility); + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s fts_feature_enable_show: Unable to allocate all_strbuff! ERROR %08X\n", + tag, ERROR_ALLOC); + } + + feature_feasibility = ERROR_OP_NOT_ALLOW; + return count; +} +#else + +#ifdef GRIP_MODE +/** + * File node to set the grip mode + * echo 01/00 > grip_mode to enable/disable glove mode \n + * cat grip_mode to show the status of the grip_enabled switch \n + * echo 01/00 > grip_mode; cat grip_mode to enable/disable grip mode and see the switch status in just one call \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent the value info->grip_enabled (1 = enabled; 0= disabled) \n + * } = end byte + */ +static ssize_t fts_grip_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(0, "%s %s: grip_enabled = %d \n", tag, __func__, + info->grip_enabled); + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + + index += + snprintf(&all_strbuff[index], 13, "{ %08X }", + info->grip_enabled); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + +static ssize_t fts_grip_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct fts_ts_info *info = dev_get_drvdata(dev); + +/*in case of a different elaboration of the input, just modify this initial part of the code according to customer needs*/ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s: Number of bytes of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + } else { + sscanf(p, "%02X ", &temp); + p += 3; +/* +*this is a standard code that should be always used when a feature is enabled! +*first step : check if the wanted feature can be enabled +*second step: call fts_mode_handler to actually enable it +*NOTE: Disabling a feature is always allowed by default +*/ + res = check_feature_feasibility(info, FEAT_SEL_GRIP); + if (res >= OK || temp == FEAT_DISABLE) { + info->grip_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, + "%s %s: Error during fts_mode_handler! ERROR %08X\n", + tag, __func__, res); + } + } + } + return count; +} +#endif + +#ifdef CHARGER_MODE +/** + * File node to set the glove mode + * echo XX/00 > charger_mode to value >0 to enable (possible values: @link charger_opt Charger Options @endlink),00 to disable charger mode \n + * cat charger_mode to show the status of the charger_enabled switch \n + * echo 01/00 > charger_mode; cat charger_mode to enable/disable charger mode and see the switch status in just one call \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent the value info->charger_enabled (>0 = enabled; 0= disabled) \n + * } = end byte + */ +static ssize_t fts_charger_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(0, "%s %s: charger_enabled = %d \n", tag, __func__, + info->charger_enabled); + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + index += + snprintf(&all_strbuff[index], 13, "{ %08X }", + info->charger_enabled); + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + +static ssize_t fts_charger_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct fts_ts_info *info = dev_get_drvdata(dev); + +/*in case of a different elaboration of the input, just modify this initial part of the code according to customer needs*/ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s: Number of bytes of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + } else { + sscanf(p, "%02X ", &temp); + p += 3; +/* +*this is a standard code that should be always used when a feature is enabled! +*first step : check if the wanted feature can be enabled +*second step: call fts_mode_handler to actually enable it +*NOTE: Disabling a feature is always allowed by default +*/ + res = check_feature_feasibility(info, FEAT_SEL_CHARGER); + if (res >= OK || temp == FEAT_DISABLE) { + info->charger_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, + "%s %s: Error during fts_mode_handler! ERROR %08X\n", + tag, __func__, res); + } + } + } + return count; +} +#endif + +#ifdef GLOVE_MODE +/** + * File node to set the glove mode + * echo 01/00 > glove_mode to enable/disable glove mode \n + * cat glove_mode to show the status of the glove_enabled switch \n + * echo 01/00 > glove_mode; cat glove_mode to enable/disable glove mode and see the switch status in just one call \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent the of value info->glove_enabled (1 = enabled; 0= disabled) \n + * } = end byte + */ +static ssize_t fts_glove_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(0, "%s %s: glove_enabled = %d \n", tag, __func__, + info->glove_enabled); + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + + index += + snprintf(&all_strbuff[index], 13, "{ %08X }", + info->glove_enabled); + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + +static ssize_t fts_glove_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct fts_ts_info *info = dev_get_drvdata(dev); + +/*in case of a different elaboration of the input, just modify this initial part of the code according to customer needs*/ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s: Number of bytes of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + } else { + sscanf(p, "%02X ", &temp); + p += 3; +/* +*this is a standard code that should be always used when a feature is enabled! +*first step : check if the wanted feature can be enabled +*second step: call fts_mode_handler to actually enable it +*NOTE: Disabling a feature is always allowed by default +*/ + res = check_feature_feasibility(info, FEAT_SEL_GLOVE); + if (res >= OK || temp == FEAT_DISABLE) { + info->glove_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, + "%s %s: Error during fts_mode_handler! ERROR %08X\n", + tag, __func__, res); + } + } + } + + return count; +} +#endif + +#ifdef COVER_MODE +/** + * File node to set the cover mode + * echo 01/00 > cover_mode to enable/disable cover mode \n + * cat cover_mode to show the status of the cover_enabled switch \n + * echo 01/00 > cover_mode; cat cover_mode to enable/disable cover mode and see the switch status in just one call \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which is the value of info->cover_enabled (1 = enabled; 0= disabled)\n + * } = end byte\n + * NOTE: \n + * the cover can be handled also using a notifier, in this case the body of these functions should be copied in the notifier callback + */ +static ssize_t fts_cover_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(0, "%s %s: cover_enabled = %d \n", tag, __func__, + info->cover_enabled); + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + + index += + snprintf(&all_strbuff[index], 13, "{ %08X }", + info->cover_enabled); + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + +static ssize_t fts_cover_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + int res; + struct fts_ts_info *info = dev_get_drvdata(dev); + +/*in case of a different elaboration of the input, just modify this initial part of the code according to customer needs*/ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s: Number of bytes of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + } else { + sscanf(p, "%02X ", &temp); + p += 3; +/* +*this is a standard code that should be always used when a feature is enabled! +*first step : check if the wanted feature can be enabled +*second step: call fts_mode_handler to actually enable it +*NOTE: Disabling a feature is always allowed by default +*/ + res = check_feature_feasibility(info, FEAT_SEL_COVER); + if (res >= OK || temp == FEAT_DISABLE) { + info->cover_enabled = temp; + res = fts_mode_handler(info, 1); + if (res < OK) { + logError(1, + "%s %s: Error during fts_mode_handler! ERROR %08X\n", + tag, __func__, res); + } + } + } + + return count; +} +#endif + +#ifdef STYLUS_MODE +/** + * File node to enable the stylus report + * echo 01/00 > stylus_mode to enable/disable stylus mode\n + * cat stylus_mode to show the status of the stylus_enabled switch\n + * echo 01/00 > stylus_mode; cat stylus_mode to enable/disable stylus mode and see the switch status in just one call\n + * the string returned in the shell is made up as follow:\n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which is the value of info->stylus_enabled (1 = enabled; 0= disabled)\n + * } = end byte + */ +static ssize_t fts_stylus_mode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(0, "%s %s: stylus_enabled = %d \n", tag, __func__, + info->stylus_enabled); + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + + index += + snprintf(&all_strbuff[index], 13, "{ %08X }", + info->stylus_enabled); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + + return count; +} + +static ssize_t fts_stylus_mode_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + unsigned int temp; + struct fts_ts_info *info = dev_get_drvdata(dev); + +/*in case of a different elaboration of the input, just modify this initial part of the code according to customer needs*/ + if ((count + 1) / 3 != 1) { + logError(1, + "%s %s: Number of bytes of parameter wrong! %d != %d byte\n", + tag, __func__, (count + 1) / 3, 1); + } else { + sscanf(p, "%02X ", &temp); + p += 3; + info->stylus_enabled = temp; + + } + return count; +} +#endif + +#endif + +/***************************************** GESTURES ***************************************************/ +#ifdef GESTURE_MODE +#ifdef USE_GESTURE_MASK +/** + * File node used by the host to set the gesture mask to enable or disable + * echo EE X1 X2 ~~ > gesture_mask set the gesture to disable/enable; EE = 00(disable) or 01(enable)\n + * X1 ~~ = gesture mask (example 06 00 ~~ 00 this gesture mask represents the gestures with ID = 1 and 2) can be specified from 1 to GESTURE_MASK_SIZE bytes,\n + * if less than GESTURE_MASK_SIZE bytes are passed as arguments, the omit bytes of the mask maintain the previous settings\n + * if one or more gestures is enabled the driver will automatically enable the gesture mode, If all the gestures are disabled the driver automatically will disable the gesture mode\n + * cat gesture_mask set inside the specified mask and return an error code for the operation \n + * the string returned in the shell is made up as follow:\n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent an error code for enabling the mask (00000000 = no error)\n + * } = end byte \n\n + * if USE_GESTURE_MASK is not define the usage of the function become: \n\n + * echo EE X1 X2 ~~ > gesture_mask set the gesture to disable/enable; EE = 00(disable) or 01(enable)\n + * X1 ~~ = gesture IDs (example 01 02 05 represent the gestures with ID = 1, 2 and 5) there is no limit of the IDs passed as arguments, (@link gesture_opt Gesture IDs @endlink)\n + * if one or more gestures is enabled the driver will automatically enable the gesture mode. If all the gestures are disabled the driver automatically will disable the gesture mode.\n + * cat gesture_mask to show the status of the gesture enabled switch \n + * the string returned in the shell is made up as follow:\n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which is the value of info->gesture_enabled (1 = enabled; 0= disabled)\n + * } = end byte + */ +static ssize_t fts_gesture_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0, res, temp; + struct fts_ts_info *info = dev_get_drvdata(dev); + + if (mask[0] == 0) { + res = ERROR_OP_NOT_ALLOW; + logError(1, + "%s %s: Call before echo enable/disable xx xx .... > gesture_mask with a correct number of parameters! ERROR %08X \n", + tag, __func__, res); + } else { + + if (mask[1] == FEAT_ENABLE || mask[1] == FEAT_DISABLE) + res = updateGestureMask(&mask[2], mask[0], mask[1]); + else + res = ERROR_OP_NOT_ALLOW; + + if (res < OK) { + logError(1, "%s fts_gesture_mask_store: ERROR %08X \n", + tag, res); + } + } + res |= check_feature_feasibility(info, FEAT_SEL_GESTURE); + temp = isAnyGestureActive(); + if (res >= OK || temp == FEAT_DISABLE) { + info->gesture_enabled = temp; + } + + logError(1, "%s fts_gesture_mask_store: Gesture Enabled = %d \n", tag, + info->gesture_enabled); + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + + index += snprintf(&all_strbuff[index], 13, "{ %08X }", res); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s fts_gesture_mask_show: Unable to allocate all_strbuff! ERROR %08X\n", + tag, ERROR_ALLOC); + } + + mask[0] = 0; + return count; +} + +static ssize_t fts_gesture_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + int n; + unsigned int temp; + + if ((count + 1) / 3 > GESTURE_MASK_SIZE + 1) { + logError(1, + "%s fts_gesture_mask_store: Number of bytes of parameter wrong! %d > (enable/disable + %d )\n", + tag, (count + 1) / 3, GESTURE_MASK_SIZE); + mask[0] = 0; + } else { + mask[0] = ((count + 1) / 3) - 1; + for (n = 1; n <= (count + 1) / 3; n++) { + sscanf(p, "%02X ", &temp); + p += 3; + mask[n] = (u8) temp; + logError(0, "%s mask[%d] = %02X \n", tag, n, mask[n]); + + } + } + + return count; +} + +#else +/** + * File node used by the host to set the gesture mask to enable or disable + * echo EE X1 X2 ~~ > gesture_mask set the gesture to disable/enable; EE = 00(disable) or 01(enable)\n + * X1 ~ = gesture IDs (example 01 02 05 represent the gestures with ID = 1, 2 and 5) there is no limit of the IDs passed as arguments, (@link gesture_opt Gesture IDs @endlink) \n + * if one or more gestures is enabled the driver will automatically enable the gesture mode, If all the gestures are disabled the driver automatically will disable the gesture mode \n + * cat gesture_mask to show the status of the gesture enabled switch \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which is the value of info->gesture_enabled (1 = enabled; 0= disabled)\n + * } = end byte + */ +static ssize_t fts_gesture_mask_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(0, "%s fts_gesture_mask_show: gesture_enabled = %d \n", tag, + info->gesture_enabled); + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + + index += + snprintf(&all_strbuff[index], 13, "{ %08X }", + info->gesture_enabled); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s fts_gesture_mask_show: Unable to allocate all_strbuff! ERROR %08X\n", + tag, ERROR_ALLOC); + } + + return count; +} + +static ssize_t fts_gesture_mask_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + char *p = (char *)buf; + int n; + unsigned int temp; + int res; + struct fts_ts_info *info = dev_get_drvdata(dev); + + if ((count + 1) / 3 < 2 || (count + 1) / 3 > GESTURE_MASK_SIZE + 1) { + logError(1, + "%s fts_gesture_mask_store: Number of bytes of parameter wrong! %d < or > (enable/disable + at least one gestureID or max %d bytes)\n", + tag, (count + 1) / 3, GESTURE_MASK_SIZE); + mask[0] = 0; + } else { + memset(mask, 0, GESTURE_MASK_SIZE + 2); + mask[0] = ((count + 1) / 3) - 1; + sscanf(p, "%02X ", &temp); + p += 3; + mask[1] = (u8) temp; + for (n = 1; n < (count + 1) / 3; n++) { + sscanf(p, "%02X ", &temp); + p += 3; + fromIDtoMask((u8) temp, &mask[2], GESTURE_MASK_SIZE); + + } + + for (n = 0; n < GESTURE_MASK_SIZE + 2; n++) { + logError(1, "%s mask[%d] = %02X \n", tag, n, mask[n]); + + } + + } + + if (mask[0] == 0) { + res = ERROR_OP_NOT_ALLOW; + logError(1, + "%s %s: Call before echo enable/disable xx xx .... > gesture_mask with a correct number of parameters! ERROR %08X \n", + tag, __func__, res); + } else { + + if (mask[1] == FEAT_ENABLE || mask[1] == FEAT_DISABLE) + res = updateGestureMask(&mask[2], mask[0], mask[1]); + else + res = ERROR_OP_NOT_ALLOW; + + if (res < OK) { + logError(1, "%s fts_gesture_mask_store: ERROR %08X \n", + tag, res); + } + + } + + res = check_feature_feasibility(info, FEAT_SEL_GESTURE); + temp = isAnyGestureActive(); + if (res >= OK || temp == FEAT_DISABLE) { + info->gesture_enabled = temp; + } + res = fts_mode_handler(info, 0); + + return count; +} + +#endif + +/** + * File node to read the coordinates of the last gesture drawn by the user \n + * cat gesture_coordinates to obtain the gesture coordinates \n + * the string returned in the shell follow this up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent an error code (00000000 no error) \n + * \n if error code = 00000000 \n + * CC = 1 byte in HEX format number of coords (pair of x,y) returned \n + * XXiYYi ... = XXi 2 bytes in HEX format for x[i] and YYi 2 bytes in HEX format for y[i] (big endian) \n + * \n + * } = end byte + */ +static ssize_t fts_gesture_coordinates_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int size = (6 * 2) + 1, index = 0; + u8 *all_strbuff = NULL; + int count = 0, res, i = 0; + + logError(0, "%s %s: Getting gestures coordinates... \n", tag, __func__); + + if (gesture_coords_reported < OK) { + logError(1, "%s %s: invalid coordinates! ERROR %08X \n", tag, + __func__, gesture_coords_reported); + res = gesture_coords_reported; + } else { + size += gesture_coords_reported * 2 * 4 + 2; + res = OK; + } + + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + if (all_strbuff != NULL) { + + snprintf(&all_strbuff[index], 11, "{ %08X", res); + index += 10; + + if (res >= OK) { + snprintf(&all_strbuff[index], 3, "%02X", + gesture_coords_reported); + index += 2; + + for (i = 0; i < gesture_coords_reported; i++) { + snprintf(&all_strbuff[index], 5, "%04X", + gesture_coordinates_x[i]); + index += 4; + snprintf(&all_strbuff[index], 5, "%04X", + gesture_coordinates_y[i]); + index += 4; + } + } + + index += snprintf(&all_strbuff[index], 3, " }"); + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + logError(0, "%s %s: Getting gestures coordinates FINISHED! \n", + tag, __func__); + + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, ERROR_ALLOC); + } + + return count; +} +#endif + +/***************************************** PRODUCTION TEST ***************************************************/ + +/** + * File node to execute the Mass Production Test or to get data from the IC (raw or ms/ss init data) + * echo cmd > stm_fts_cmd to execute a command \n + * cat stm_fts_cmd to show the result of the command \n + * echo cmd > stm_fts_cmd; cat stm_fts_cmd to execute and show the result in just one call \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * X1X2X3X4 = 4 bytes in HEX format which represent an error_code (00000000 = OK)\n + * (optional) data = data coming from the command executed represented as HEX string \n + * Not all the command return additional data \n + * } = end byte + * \n + * Possible commands (cmd): \n + * - 00 = MP Test -> return erro_code \n + * - 01 = ITO Test -> return error_code \n + * - 03 = MS Raw Test -> return error_code \n + * - 04 = MS Init Data Test -> return error_code \n + * - 05 = SS Raw Test -> return error_code \n + * - 06 = SS Init Data Test -> return error_code \n + * - 13 = Read 1 MS Raw Frame -> return additional data: MS frame row after row \n + * - 14 = Read MS Init Data -> return additional data: MS init data row after row \n + * - 15 = Read 1 SS Raw Frame -> return additional data: SS frame, force channels followed by sense channels \n + * - 16 = Read SS Init Data -> return additional data: SS Init data, first IX for force and sense channels and then CX for force and sense channels \n + * - F0 = Perform a system reset -> return error_code \n + * - F1 = Perform a system reset and reenable the sensing and the interrupt + */ +static ssize_t stm_fts_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + int n; + char *p = (char *)buf; + + memset(typeOfComand, 0, CMD_STR_LEN * sizeof(u32)); + + logError(1, "%s \n", tag); + for (n = 0; n < (count + 1) / 3; n++) { + sscanf(p, "%02X ", &typeOfComand[n]); + p += 3; + logError(1, "%s typeOfComand[%d] = %02X \n", tag, n, + typeOfComand[n]); + + } + + numberParameters = n; + logError(1, "%s Number of Parameters = %d \n", tag, numberParameters); + return count; +} + +static ssize_t stm_fts_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int res, j, doClean = 0, count = 0, index = 0; + char buff[CMD_STR_LEN] = { 0 }; + + int size = (6 * 2) + 1; + int init_type = SPECIAL_PANEL_INIT; + u8 *all_strbuff = NULL; + const char *limit_file_name = NULL; + struct fts_ts_info *info = dev_get_drvdata(dev); + + MutualSenseData compData; + SelfSenseData comData; + MutualSenseFrame frameMS; + SelfSenseFrame frameSS; + + if (numberParameters >= 1) { + res = fts_disableInterrupt(); + if (res < 0) { + logError(0, "%s fts_disableInterrupt: ERROR %08X \n", + tag, res); + res = (res | ERROR_DISABLE_INTER); + goto END; + } +#ifdef CONFIG_DRM + res = msm_drm_unregister_client(&info->notifier); + if (res < 0) { + logError(1, "%s ERROR: unregister notifier failed!\n", + tag); + goto END; + } +#endif + switch (typeOfComand[0]) { + /*ITO TEST */ + case 0x01: + res = production_test_ito(LIMITS_FILE, &tests); + break; + /*PRODUCTION TEST */ + case 0x00: + + if (systemInfo.u8_cfgAfeVer != systemInfo.u8_cxAfeVer) { + res = ERROR_OP_NOT_ALLOW; + logError(0, + "%s Miss match in CX version! MP test not allowed with wrong CX memory! ERROR %08X \n", + tag, res); + break; + } + + limit_file_name = fts_get_limit(info); + res = + production_test_main(LIMITS_FILE, 1, init_type, + &tests); + break; + /*read mutual raw */ + case 0x13: + logError(0, "%s Get 1 MS Frame \n", tag); + setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + flushFIFO(); + res = getMSFrame3(MS_RAW, &frameMS); + if (res < 0) { + logError(0, + "%s Error while taking the MS frame... ERROR %08X \n", + tag, res); + + } else { + logError(0, "%s The frame size is %d words\n", + tag, res); + size = (res * (sizeof(short) * 2 + 1)) + 10; + res = OK; + print_frame_short("MS frame =", + array1dTo2d_short + (frameMS.node_data, + frameMS.node_data_size, + frameMS.header.sense_node), + frameMS.header.force_node, + frameMS.header.sense_node); + } + break; + /*read self raw */ + case 0x15: + logError(0, "%s Get 1 SS Frame \n", tag); + setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + flushFIFO(); + res = getSSFrame3(SS_RAW, &frameSS); + + if (res < OK) { + logError(0, + "%s Error while taking the SS frame... ERROR %08X \n", + tag, res); + + } else { + logError(0, "%s The frame size is %d words\n", + tag, res); + size = (res * (sizeof(short) * 2 + 1)) + 10; + res = OK; + print_frame_short("SS force frame =", + array1dTo2d_short + (frameSS.force_data, + frameSS.header.force_node, + 1), + frameSS.header.force_node, 1); + print_frame_short("SS sense frame =", + array1dTo2d_short + (frameSS.sense_data, + frameSS.header.sense_node, + frameSS.header.sense_node), + 1, frameSS.header.sense_node); + } + + break; + + case 0x14: + logError(0, "%s Get MS Compensation Data \n", tag); + res = + readMutualSenseCompensationData(LOAD_CX_MS_TOUCH, + &compData); + + if (res < 0) { + logError(0, + "%s Error reading MS compensation data ERROR %08X \n", + tag, res); + } else { + logError(0, + "%s MS Compensation Data Reading Finished! \n", + tag); + size = + (compData.node_data_size * sizeof(u8)) * 3 + + 1; + print_frame_i8("MS Data (Cx2) =", + array1dTo2d_i8 + (compData.node_data, + compData.node_data_size, + compData.header.sense_node), + compData.header.force_node, + compData.header.sense_node); + } + break; + + case 0x16: + logError(0, "%s Get SS Compensation Data... \n", tag); + res = + readSelfSenseCompensationData(LOAD_CX_SS_TOUCH, + &comData); + if (res < 0) { + logError(0, + "%s Error reading SS compensation data ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s SS Compensation Data Reading Finished! \n", + tag); + size = + ((comData.header.force_node + + comData.header.sense_node) * 2 + + 12) * sizeof(u8) * 2 + 1; + print_frame_u8("SS Data Ix2_fm = ", + array1dTo2d_u8(comData.ix2_fm, + comData. + header.force_node, + 1), + comData.header.force_node, 1); + print_frame_i8("SS Data Cx2_fm = ", + array1dTo2d_i8(comData.cx2_fm, + comData. + header.force_node, + 1), + comData.header.force_node, 1); + print_frame_u8("SS Data Ix2_sn = ", + array1dTo2d_u8(comData.ix2_sn, + comData. + header.sense_node, + comData. + header.sense_node), + 1, comData.header.sense_node); + print_frame_i8("SS Data Cx2_sn = ", + array1dTo2d_i8(comData.cx2_sn, + comData. + header.sense_node, + comData. + header.sense_node), + 1, comData.header.sense_node); + } + break; + + case 0x03: + res = fts_system_reset(); + if (res >= OK) + res = + production_test_ms_raw(LIMITS_FILE, 1, + &tests); + break; + + case 0x04: + res = fts_system_reset(); + if (res >= OK) + res = + production_test_ms_cx(LIMITS_FILE, 1, + &tests); + break; + + case 0x05: + res = fts_system_reset(); + if (res >= OK) + res = + production_test_ss_raw(LIMITS_FILE, 1, + &tests); + break; + + case 0x06: + res = fts_system_reset(); + if (res >= OK) + res = + production_test_ss_ix_cx(LIMITS_FILE, 1, + &tests); + break; + + case 0xF0: + case 0xF1: + doClean = (int)(typeOfComand[0] & 0x01); + res = cleanUp(doClean); + break; + + default: + logError(1, + "%s COMMAND NOT VALID!! Insert a proper value ...\n", + tag); + res = ERROR_OP_NOT_ALLOW; + break; + } + + doClean = fts_mode_handler(info, 1); + if (typeOfComand[0] != 0xF0) + doClean |= fts_enableInterrupt(); + if (doClean < 0) { + logError(0, "%s %s: ERROR %08X \n", tag, __func__, + (doClean | ERROR_ENABLE_INTER)); + } + } else { + logError(1, + "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", + tag); + res = ERROR_OP_NOT_ALLOW; + + } +#ifdef CONFIG_DRM + if (msm_drm_register_client(&info->notifier) < 0) { + logError(1, "%s ERROR: register notifier failed!\n", tag); + } +#endif +END: + all_strbuff = (u8 *) kzalloc(size, GFP_KERNEL); + + if (res >= OK) { + /*all the other cases are already fine printing only the res. */ + switch (typeOfComand[0]) { + case 0x13: + snprintf(all_strbuff, size, "ms_frame\n"); + for (j = 0; j < frameMS.node_data_size; j++) { + if ((j + 1) % frameMS.header.sense_node) + snprintf(buff, sizeof(buff), "%04d ", + frameMS.node_data[j]); + else + snprintf(buff, sizeof(buff), "%04d\n", + frameMS.node_data[j]); + + strlcat(all_strbuff, buff, size); + } + + kfree(frameMS.node_data); + frameMS.node_data = NULL; + break; + + case 0x15: + snprintf(all_strbuff, size, "ss_frame\n"); + for (j = 0; j < frameSS.header.force_node - 1; j++) { + snprintf(buff, sizeof(buff), "%04d ", + frameSS.force_data[j]); + strlcat(all_strbuff, buff, size); + } + + if (j == frameSS.header.force_node - 1) { + snprintf(buff, sizeof(buff), "%04d\n", + frameSS.force_data[j]); + strlcat(all_strbuff, buff, size); + } + + for (j = 0; j < frameSS.header.sense_node - 1; j++) { + snprintf(buff, sizeof(buff), "%04d ", + frameSS.sense_data[j]); + strlcat(all_strbuff, buff, size); + } + + if (j == frameSS.header.sense_node - 1) { + snprintf(buff, sizeof(buff), "%04d\n", + frameSS.sense_data[j]); + strlcat(all_strbuff, buff, size); + } + + kfree(frameSS.force_data); + kfree(frameSS.sense_data); + + break; + + case 0x14: + snprintf(buff, sizeof(buff), "%02X", + (u8) compData.header.force_node); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + (u8) compData.header.sense_node); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", compData.cx1); + strlcat(all_strbuff, buff, size); + + for (j = 0; j < compData.node_data_size; j++) { + snprintf(buff, sizeof(buff), "%02X", + *(compData.node_data + j)); + strlcat(all_strbuff, buff, size); + } + + kfree(compData.node_data); + compData.node_data = NULL; + + break; + + case 0x16: + snprintf(buff, sizeof(buff), "%02X", + comData.header.force_node); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", + comData.header.sense_node); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", comData.f_ix1); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", comData.s_ix1); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", comData.f_cx1); + strlcat(all_strbuff, buff, size); + snprintf(buff, sizeof(buff), "%02X", comData.s_cx1); + strlcat(all_strbuff, buff, size); + + for (j = 0; j < comData.header.force_node; j++) { + snprintf(buff, sizeof(buff), "%02X", + comData.ix2_fm[j]); + strlcat(all_strbuff, buff, size); + } + + for (j = 0; j < comData.header.sense_node; j++) { + snprintf(buff, sizeof(buff), "%02X", + comData.ix2_sn[j]); + strlcat(all_strbuff, buff, size); + } + + for (j = 0; j < comData.header.force_node; j++) { + snprintf(buff, sizeof(buff), "%02X", + comData.cx2_fm[j]); + strlcat(all_strbuff, buff, size); + } + + for (j = 0; j < comData.header.sense_node; j++) { + snprintf(buff, sizeof(buff), "%02X", + comData.cx2_sn[j]); + strlcat(all_strbuff, buff, size); + } + + kfree(comData.ix2_fm); + kfree(comData.ix2_sn); + kfree(comData.cx2_fm); + kfree(comData.cx2_sn); + + break; + + default: + snprintf(&all_strbuff[index], 11, "{ %08X", res); + index += 10; + snprintf(&all_strbuff[index], 3, " }"); + index += 2; + + break; + + } + } else { + snprintf(&all_strbuff[index], 11, "{ %08X", res); + index += 10; + snprintf(&all_strbuff[index], 3, " }"); + index += 2; + } + + count = snprintf(buf, TSP_BUF_SIZE, "%s\n", all_strbuff); + numberParameters = 0; + kfree(all_strbuff); + + return count; +} + +static ssize_t fts_panel_color_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%c\n", info->lockdown_info[2]); +} + +static ssize_t fts_panel_vendor_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%c\n", info->lockdown_info[6]); +} + +static ssize_t fts_panel_display_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + return snprintf(buf, PAGE_SIZE, "%c\n", info->lockdown_info[1]); +} + +static ssize_t fts_lockdown_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + int ret; + ret = fts_get_lockdown_info(info->lockdown_info, info); + + if (ret != OK) { + logError(1, "%s get lockdown info error\n", tag); + return 0; + } + + return snprintf(buf, PAGE_SIZE, + "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", + info->lockdown_info[0], info->lockdown_info[1], + info->lockdown_info[2], info->lockdown_info[3], + info->lockdown_info[4], info->lockdown_info[5], + info->lockdown_info[6], info->lockdown_info[7]); +} + +static ssize_t fts_lockdown_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int n, i, ret; + char *p = (char *)buf; + u8 *typecomand = NULL; + + memset(typeOfComand, 0, CMD_STR_LEN * sizeof(u32)); + logError(1, "%s \n", tag); + for (n = 0; n < (count + 1) / 3; n++) { + sscanf(p, "%02X ", &typeOfComand[n]); + p += 3; + logError(1, "%s command_sequence[%d] = %02X\n", tag, n, + typeOfComand[n]); + } + numberParameters = n; + if (numberParameters < 3) + goto END; + logError(1, "%s %d = %d \n", tag, n, numberParameters); + + typecomand = + (u8 *) kmalloc((numberParameters - 2) * sizeof(u8), GFP_KERNEL); + if (typecomand != NULL) { + for (i = 0; i < numberParameters - 2; i++) { + typecomand[i] = (u8) typeOfComand[i + 2]; + logError(1, "%s typecomand[%d] = %X \n", tag, i, + typecomand[i]); + } + } else { + goto END; + } + + ret = + writeLockDownInfo(typecomand, numberParameters - 2, + typeOfComand[0]); + if (ret < 0) { + logError(1, "%s fts_lockdown_store failed\n", tag); + } + kfree(typecomand); +END: + logError(1, "%s Number of Parameters = %d \n", tag, numberParameters); + + return count; +} + +static ssize_t fts_lockdown_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int i, ret; + int size = 0, count = 0; + u8 type; + u8 *temp_buffer = NULL; + + temp_buffer = (u8 *) kmalloc(LOCKDOWN_LENGTH * sizeof(u8), GFP_KERNEL); + if (temp_buffer == NULL || numberParameters < 2) { + count += + snprintf(&buf[count], PAGE_SIZE, "prepare read lockdown failded\n"); + return count; + } + type = typeOfComand[0]; + size = (int)(typeOfComand[1]); + count += snprintf(&buf[count], PAGE_SIZE, "read lock down code:\n"); + ret = readLockDownInfo(temp_buffer, type, size); + if (ret < OK) { + count += snprintf(&buf[count], PAGE_SIZE, "read lockdown failded\n"); + goto END; + } + for (i = 0; i < size; i++) { + count += snprintf(&buf[count], PAGE_SIZE, "%02X ", temp_buffer[i]); + } + count += snprintf(&buf[count], PAGE_SIZE, "\n"); + +END: + numberParameters = 0; + kfree(temp_buffer); + return count; +} + +static ssize_t fts_selftest_info_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int res = 0, i = 0, count = 0, force_node = 0, sense_node = 0, pos = + 0, last_pos = 0; + MutualSenseFrame frameMS; + char buff[80]; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + + res = fts_disableInterrupt(); + if (res < OK) + goto END; + + setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + flushFIFO(); + res = getMSFrame3(MS_RAW, &frameMS); + if (res < 0) { + logError(0, + "%s Error while taking the MS frame... ERROR %08X \n", + tag, res); + goto END; + } + fts_mode_handler(info, 1); + + sense_node = frameMS.header.sense_node; + force_node = frameMS.header.force_node; + + for (i = 0; i < RELEASE_INFO_SIZE; i++) { + if (i == 0) { + pos += + snprintf(buff + last_pos, PAGE_SIZE, "0x%02x", + systemInfo.u8_releaseInfo[i]); + last_pos = pos; + } else { + pos += + snprintf(buff + last_pos, PAGE_SIZE, "%02x", + systemInfo.u8_releaseInfo[i]); + last_pos = pos; + } + } + count = + snprintf(buf, PAGE_SIZE, + "Device address:,0x49\nChip Id:,0x%04x\nFw version:,0x%04x\nConfig version:,0x%04x\nChip serial number:,%s\nForce lines count:,%02d\nSense lines count:,%02d\n\n", + systemInfo.u16_chip0Id, systemInfo.u16_fwVer, + systemInfo.u16_cfgVer, buff, force_node, sense_node); +END: + fts_enableInterrupt(); + return count; + +} + +static ssize_t fts_ms_raw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int res = 0, count = 0, j = 0, sense_node = 0, force_node = 0, pos = + 0, last_pos = 0; + char *all_strbuff = NULL; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + MutualSenseFrame frameMS; + + res = fts_disableInterrupt(); + if (res < OK) + goto END; + all_strbuff = vmalloc(PAGE_SIZE); + if (!all_strbuff) { + logError(1, "%s %s alloc all_strbuff fail\n", tag, __func__); + goto END; + } else + memset(all_strbuff, 0, PAGE_SIZE); + + setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + flushFIFO(); + res = getMSFrame3(MS_RAW, &frameMS); + + fts_mode_handler(info, 1); + sense_node = frameMS.header.sense_node; + force_node = frameMS.header.force_node; + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "MsTouchRaw,%2d,%2d\n ,", force_node, sense_node); + last_pos = pos; + if (res >= OK) { + for (j = 0; j < sense_node; j++) + if ((j + 1) % sense_node) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "C%02d,", j); + last_pos = pos; + } else { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "C%02d\nR00,", j); + last_pos = pos; + } + for (j = 0; j < sense_node * force_node; j++) { + if ((j + 1) % sense_node) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%4d,", frameMS.node_data[j]); + last_pos = pos; + } else { + if ((j + 1) / sense_node != force_node) + pos += + snprintf(all_strbuff + last_pos, + PAGE_SIZE, "%4d\nR%02d,", + frameMS.node_data[j], + (j + 1) / sense_node); + else + pos += + snprintf(all_strbuff + last_pos, + PAGE_SIZE, "%4d\n", + frameMS.node_data[j]); + last_pos = pos; + } + } + if (frameMS.node_data) { + kfree(frameMS.node_data); + frameMS.node_data = NULL; + } + } + + count = snprintf(buf, PAGE_SIZE, "%s\n", all_strbuff); + vfree(all_strbuff); +END: + fts_enableInterrupt(); + return count; +} + +static ssize_t fts_ms_cx_total_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int res = 0, pos = 0, last_pos = 0, count = 0, j = 0, sense_node = + 0, force_node = 0; + char *all_strbuff = NULL; + TotMutualSenseData totCompData; + + res = fts_disableInterrupt(); + if (res < OK) + goto END; + all_strbuff = vmalloc(PAGE_SIZE); + if (!all_strbuff) { + logError(1, "%s %s alloc all_strbuff fail\n", tag, __func__); + goto END; + } else + memset(all_strbuff, 0, PAGE_SIZE); + + res = + readTotMutualSenseCompensationData(LOAD_PANEL_CX_TOT_MS_TOUCH, + &totCompData); + if (res >= OK) { + sense_node = totCompData.header.sense_node; + force_node = totCompData.header.force_node; + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "MsTouchTotalCx,%2d,%2d\n ,", force_node, + sense_node); + last_pos = pos; + for (j = 0; j < sense_node; j++) + if ((j + 1) % sense_node) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "C%02d,", j); + last_pos = pos; + } else { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "C%02d\nR00,", j); + last_pos = pos; + } + for (j = 0; j < sense_node * force_node; j++) { + if ((j + 1) % sense_node) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%4d,", totCompData.node_data[j]); + last_pos = pos; + } else { + if ((j + 1) / sense_node != force_node) + pos += + snprintf(all_strbuff + last_pos, + PAGE_SIZE, "%4d\nR%02d,", + totCompData.node_data[j], + (j + 1) / sense_node); + else + pos += + snprintf(all_strbuff + last_pos, + PAGE_SIZE, "%4d\n", + totCompData.node_data[j]); + last_pos = pos; + } + } + if (totCompData.node_data) { + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } + } + + count = snprintf(buf, PAGE_SIZE, "%s\n", all_strbuff); + vfree(all_strbuff); +END: + fts_enableInterrupt(); + return count; + +} + +static ssize_t fts_ss_ix_total_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int ret = 0, pos = 0, last_pos = 0, count = 0, j = 0, sense_node = + 0, force_node = 0; + char *all_strbuff = NULL; + TotSelfSenseData totCompData; + + ret = fts_disableInterrupt(); + if (ret < OK) + goto END; + all_strbuff = vmalloc(PAGE_SIZE); + if (!all_strbuff) { + logError(1, "%s %s alloc all_strbuff fail\n", tag, __func__); + goto END; + } else { + memset(all_strbuff, 0, PAGE_SIZE); + } + ret = + readTotSelfSenseCompensationData(LOAD_PANEL_CX_TOT_SS_TOUCH, + &totCompData); + if (ret < 0) { + logError(1, + "%s production_test_data: readTotSelfSenseCompensationData failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + goto END; + } + + sense_node = 1; + force_node = totCompData.header.force_node; + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SsTouchForceTotalIx,%2d,1\n ,C00\n", force_node); + last_pos = pos; + for (j = 0; j < force_node; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "R%02d,%4d\n", + j, totCompData.ix_fm[j]); + last_pos = pos; + } + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SsTouchForceTotalCx,%2d,1\n ,C00\n", force_node); + last_pos = pos; + for (j = 0; j < force_node; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "R%02d,%4d\n", + j, totCompData.cx_fm[j]); + last_pos = pos; + } + + sense_node = totCompData.header.sense_node; + force_node = 1; + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SsTouchsenseTotalIx,%2d,1\n ,C00\n", sense_node); + last_pos = pos; + for (j = 0; j < sense_node; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "R%02d,%4d\n", + j, totCompData.ix_sn[j]); + last_pos = pos; + } + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SsTouchsenseTotalCx,%2d,1\n ,C00\n", sense_node); + last_pos = pos; + for (j = 0; j < sense_node; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "R%02d,%4d\n", + j, totCompData.cx_sn[j]); + last_pos = pos; + } + + if (totCompData.ix_fm != NULL) { + kfree(totCompData.ix_fm); + totCompData.ix_fm = NULL; + } + + if (totCompData.cx_fm != NULL) { + kfree(totCompData.cx_fm); + totCompData.cx_fm = NULL; + } + + if (totCompData.ix_sn != NULL) { + kfree(totCompData.ix_sn); + totCompData.ix_sn = NULL; + } + + if (totCompData.cx_sn != NULL) { + kfree(totCompData.cx_sn); + totCompData.cx_sn = NULL; + } + + count = snprintf(buf, PAGE_SIZE, "%s\n", all_strbuff); + vfree(all_strbuff); +END: + fts_enableInterrupt(); + return count; +} + +static ssize_t fts_ss_raw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int res = 0, count = 0, j = 0, sense_node = 0, force_node = 0, pos = + 0, last_pos = 0; + char *all_strbuff = NULL; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + SelfSenseFrame frameSS; + + res = fts_disableInterrupt(); + if (res < OK) + goto END; + all_strbuff = vmalloc(PAGE_SIZE * 4); + if (!all_strbuff) { + logError(1, "%s %s alloc all_strbuff fail\n", tag, __func__); + goto END; + } else + memset(all_strbuff, 0, PAGE_SIZE); + setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + flushFIFO(); + res = getSSFrame3(SS_RAW, &frameSS); + + fts_mode_handler(info, 1); + sense_node = frameSS.header.sense_node; + force_node = frameSS.header.force_node; + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "SsTouchRaw,%2d,%2d\n", + force_node, sense_node); + last_pos = pos; + if (res >= OK) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS force frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.force_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.force_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.force_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.force_data[j]); + last_pos = pos; + } + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS sense frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.sense_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.sense_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.sense_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.sense_data[j]); + last_pos = pos; + } + + if (frameSS.force_data) { + kfree(frameSS.force_data); + frameSS.force_data = NULL; + } + if (frameSS.sense_data) { + kfree(frameSS.sense_data); + frameSS.sense_data = NULL; + } + + } + + count = snprintf(buf, PAGE_SIZE, "%s\n", all_strbuff); + vfree(all_strbuff); +END: + fts_enableInterrupt(); + return count; +} + +static ssize_t fts_strength_frame_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + MutualSenseFrame frame; + int res = 0, count = 0, j = 0, size = 0; + char *all_strbuff = NULL; + char buff[CMD_STR_LEN] = { 0 }; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + frame.node_data = NULL; + + res = fts_disableInterrupt(); + if (res < OK) + goto END; + + res = getMSFrame3(MS_STRENGTH, &frame); + + if (res < OK) { + logError(1, "%s %s: could not get the frame! ERROR %08X \n", + tag, __func__, res); + goto END; + } + size = (res * 5) + 11; + + /* + flushFIFO(); + */ + fts_mode_handler(info, 1); + all_strbuff = (char *)kmalloc(PAGE_SIZE * sizeof(char), GFP_KERNEL); + + if (all_strbuff != NULL) { + memset(all_strbuff, 0, size); + snprintf(all_strbuff, size, "ms_differ\n"); + if (res >= OK) { + for (j = 0; j < frame.node_data_size; j++) { + if ((j + 1) % frame.header.sense_node) + snprintf(buff, sizeof(buff), "%4d,", + frame.node_data[j]); + else + snprintf(buff, sizeof(buff), "%4d\n", + frame.node_data[j]); + + strlcat(all_strbuff, buff, size); + } + + kfree(frame.node_data); + frame.node_data = NULL; + } + + count = snprintf(buf, PAGE_SIZE, "%s\n", all_strbuff); + kfree(all_strbuff); + } else { + logError(1, + "%s %s: Unable to allocate all_strbuff! ERROR %08X\n", + tag, __func__, ERROR_ALLOC); + } + +END: + fts_enableInterrupt(); + + return count; +} + +int fts_hover_auto_tune(struct fts_ts_info *info) { + int res=OK; + u8 sett[2]; + logError(0, "%s start...\n", tag, __func__); + + fts_disableInterrupt(); + + sett[0] = 0x02; + sett[1] = 0x00; + res = writeSysCmd(SYS_CMD_SPECIAL_TUNING, sett, 2); + if (res < OK) { + logError(1, "%s fts_hover_autotune Ioffset tuning 02 00 failed ERROR %08X\n", + tag, (res | ERROR_PROD_TEST_INITIALIZATION)); + return res | ERROR_PROD_TEST_INITIALIZATION; + } + sett[0] = 0x00; + sett[1] = 0x01; + res = writeSysCmd(SYS_CMD_CX_TUNING, sett, 2); + if (res < OK) { + logError(1, "%s fts_hover_autotune autotune hover 00 01 failed ERROR %08X\n", + tag, (res | ERROR_PROD_TEST_INITIALIZATION)); + return res | ERROR_PROD_TEST_INITIALIZATION; + } + sett[0] = 0x06; + res = writeSysCmd(SYS_CMD_SAVE_FLASH, sett, 1); + if (res < OK) { + logError(1, "%s fts_hover_autotune save flash 06 failed ERROR %08X\n", + tag, (res | ERROR_PROD_TEST_INITIALIZATION)); + return res | ERROR_PROD_TEST_INITIALIZATION; + } + logError(0, "%s end...\n", tag, __func__); + + fts_enableInterrupt(); + + return res; +} + +static ssize_t fts_hover_autotune_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + int on; + int ret = 0; + + sscanf(buf, "%u", &on); + logError(1, " %s %s\n", tag, __func__); + if (on) + ret = fts_hover_auto_tune(info); + if (ret < OK) + return -1; + + return count; +} + +static ssize_t fts_hover_raw_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int res = 0, count = 0, j = 0, sense_node = 0, force_node = 0, pos = + 0, last_pos = 0; + char *all_strbuff = NULL; + struct i2c_client *client = to_i2c_client(dev); + struct fts_ts_info *info = i2c_get_clientdata(client); + SelfSenseFrame frameSS; + TotSelfSenseData ssHoverCompData; + u8 hover_cnt[4] = {0xa8, 0x0b, 0x01, 0x00}; + + res = fts_disableInterrupt(); + if (res < OK) + goto END; + all_strbuff = vmalloc(PAGE_SIZE * 4); + if (!all_strbuff) { + logError(1, "%s %s alloc all_strbuff fail\n", tag, __func__); + goto END; + } else { + memset(all_strbuff, 0, PAGE_SIZE); + } + res = fts_write_dma_safe(hover_cnt, sizeof(hover_cnt)); + if (res != OK) { + logError(1, + "%s hover clear count ERROR = %d\n",tag, res); + goto END; + } + + setScanMode(SCAN_MODE_ACTIVE, 0xFF); + + res = getSSFrame3(SS_HVR_RAW, &frameSS); + + sense_node = frameSS.header.sense_node; + force_node = frameSS.header.force_node; + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "SsHoverTouchRaw,%2d,%2d\n", + force_node, sense_node); + last_pos = pos; + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "TxRaw\n"); + last_pos = pos; + + + if (res >= OK) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover force frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.force_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.force_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.force_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.force_data[j]); + last_pos = pos; + } + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover sense frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.sense_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.sense_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.sense_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.sense_data[j]); + last_pos = pos; + } + + if (frameSS.force_data) { + kfree(frameSS.force_data); + frameSS.force_data = NULL; + } + if (frameSS.sense_data) { + kfree(frameSS.sense_data); + frameSS.sense_data = NULL; + } + + } + + res = getSSFrame3(SS_HVR_FILTER, &frameSS); + + sense_node = frameSS.header.sense_node; + force_node = frameSS.header.force_node; + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "TxFilter\n"); + last_pos = pos; + + + if (res >= OK) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover force frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.force_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.force_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.force_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.force_data[j]); + last_pos = pos; + } + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover sense frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.sense_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.sense_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.sense_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.sense_data[j]); + last_pos = pos; + } + + if (frameSS.force_data) { + kfree(frameSS.force_data); + frameSS.force_data = NULL; + } + if (frameSS.sense_data) { + kfree(frameSS.sense_data); + frameSS.sense_data = NULL; + } + + } + + res = getSSFrame3(SS_HVR_BASELINE, &frameSS); + + sense_node = frameSS.header.sense_node; + force_node = frameSS.header.force_node; + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "TxBaseline\n"); + last_pos = pos; + + + if (res >= OK) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover force frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.force_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.force_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.force_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.force_data[j]); + last_pos = pos; + } + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover sense frame\n ,"); + last_pos = pos; + + for (j = 0; j < frameSS.header.sense_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + frameSS.sense_data[j]); + last_pos = pos; + } + + if (j == frameSS.header.sense_node - 1) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "%04d\n", frameSS.sense_data[j]); + last_pos = pos; + } + + if (frameSS.force_data) { + kfree(frameSS.force_data); + frameSS.force_data = NULL; + } + + if (frameSS.sense_data) { + kfree(frameSS.sense_data); + frameSS.sense_data = NULL; + } + + } + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover IX Data\n ,"); + last_pos = pos; + + res = readTotSelfSenseCompensationData(STAPI_HOST_DATA_ID_PANEL_CX_SS_HVR, &ssHoverCompData); + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "SS Hover IX force frame\n ,"); + last_pos = pos; + for (j = 0; j < ssHoverCompData.header.force_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + ssHoverCompData.ix_fm[j]); + last_pos = pos; + } + + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, + "\nSS Hover IX sense frame\n ,"); + last_pos = pos; + + for (j = 0; j < ssHoverCompData.header.sense_node - 1; j++) { + pos += + snprintf(all_strbuff + last_pos, PAGE_SIZE, "%04d,", + ssHoverCompData.ix_sn[j]); + last_pos = pos; + } + + if (ssHoverCompData.ix_fm != NULL) + kfree(ssHoverCompData.ix_fm); + if (ssHoverCompData.ix_sn != NULL) + kfree(ssHoverCompData.ix_sn); + if (ssHoverCompData.cx_fm != NULL) + kfree(ssHoverCompData.cx_fm); + if (ssHoverCompData.cx_sn != NULL) + kfree(ssHoverCompData.cx_sn); + + count = snprintf(buf, PAGE_SIZE, "%s\n", all_strbuff); + vfree(all_strbuff); +END: + fts_mode_handler(info, 1); + fts_enableInterrupt(); + return count; +} + +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP +static ssize_t fts_touch_suspend_notify_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", fts_info->sensor_sleep); +} +#endif + +static ssize_t fts_doze_time_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + return snprintf(buf, TSP_BUF_SIZE, "%u\n", info->doze_time); +} + +static ssize_t fts_doze_time_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 cmd[4] = {FTS_CMD_CUSTOM, 0x00, 0x00, 0x00}; + int ret = 0; + u16 reg_val = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + pr_info("%s,buf:%s,count:%zu\n", __func__, buf, count); + sscanf(buf, "%u", &info->doze_time); + /*reg value * 10 represents of the num of frames ,one frame is about 8ms, the input value is ms*/ + reg_val = (info->doze_time / 8 - 1) / 10; + cmd[3] = reg_val; + ret = fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)); + if (ret < OK) { + logError(1, "%s %s: write failed...ERROR %08X !\n", tag, + __func__, ret); + return -EPERM; + } + return count; +} + +static ssize_t fts_grip_enable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + return snprintf(buf, TSP_BUF_SIZE, "%d\n", info->grip_enabled); +} + +static ssize_t fts_grip_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 cmd[3] = {FTS_CMD_FEATURE, 0x04, 0x01}; + int ret = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + pr_info("%s,buf:%s,count:%zu\n", __func__, buf, count); + sscanf(buf, "%u", &info->grip_enabled); + cmd[2] = info->grip_enabled; + ret = fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)); + if (ret < OK) { + logError(1, "%s %s: write failed...ERROR %08X !\n", tag, + __func__, ret); + return -EPERM; + } + return count; +} + +static ssize_t fts_grip_area_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + return snprintf(buf, TSP_BUF_SIZE, "%d\n", info->grip_pixel); +} + +static ssize_t fts_grip_area_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + u8 cmd[4] = {FTS_CMD_CUSTOM, 0x01, 0x01, 0x00}; + int ret = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(1, " %s %s,buf:%s,count:%zu\n", tag, __func__, buf, count); + sscanf(buf, "%u", &info->grip_pixel); + cmd[3] = info->grip_pixel; + if (atomic_read(&info->system_is_resetting)) { + logError(1, "%s %s system is resetting ,wait reset done\n", tag, __func__); + ret = wait_for_completion_timeout(&info->tp_reset_completion, msecs_to_jiffies(40)); + if (!ret) { + logError(1, "%s %s wait tp reset timeout, wrtie grip area error\n", tag, __func__); + return count; + } + } + ret = fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)); + if (ret < OK) { + logError(1, "%s %s: write failed...ERROR %08X !\n", tag, + __func__, ret); + return -EPERM; + } + return count; +} +#ifdef CONFIG_FTS_FOD_AREA_REPORT +static ssize_t fts_fod_status_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + return snprintf(buf, TSP_BUF_SIZE, "%d\n", info->fod_status); +} + +static ssize_t fts_fod_status_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(1, " %s %s buf:%c,count:%zu\n", tag, __func__, buf[0], count); + sscanf(buf, "%u", &info->fod_status); + queue_work(info->event_wq, &info->mode_handler_work); + logError(1, " %s %s end\n", tag, __func__); + + return count; +} + +static ssize_t fts_fod_test_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + int value = 0; + struct fts_ts_info *info = dev_get_drvdata(dev); + + logError(1, " %s %s,buf:%s,count:%zu\n", tag, __func__, buf, count); + sscanf(buf, "%u", &value); + if (value) { + input_report_key(info->input_dev, BTN_INFO, 1); + input_report_key(info->input_dev, KEY_INFO, 1); + input_sync(info->input_dev); + input_mt_slot(info->input_dev, 0); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1); + input_report_key(info->input_dev, BTN_TOUCH, 1); + input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); + input_report_abs(info->input_dev, ABS_MT_POSITION_X, CENTER_X); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, CENTER_Y); + input_sync(info->input_dev); + } else { + input_mt_slot(info->input_dev, 0); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 0); + input_report_key(info->input_dev, BTN_INFO, 0); + input_report_key(info->input_dev, KEY_INFO, 0); + input_sync(info->input_dev); + } + return count; +} +#endif + +#ifdef CONFIG_SECURE_TOUCH +static void fts_secure_touch_notify (struct fts_ts_info *info) +{ + /*might sleep*/ + sysfs_notify(&info->dev->kobj, NULL, "secure_touch"); + logError(1, "%s %s SECURE_NOTIFY:notify secure_touch\n", tag, __func__); +} + +static int fts_secure_stop(struct fts_ts_info *info, bool block) +{ + struct fts_secure_info *scr_info = info->secure_info; + + logError(1, "%s %s SECURE_STOP: block = %d\n", tag, __func__, (int)block); + if (atomic_read(&scr_info->st_enabled) == 0) { + logError(1, "%s %s secure touch is already disabled\n", tag, __func__); + return OK; + } + + atomic_set(&scr_info->st_pending_irqs, -1); + fts_secure_touch_notify(info); + if (block) { + if (wait_for_completion_interruptible(&scr_info->st_powerdown) == -ERESTARTSYS) { + logError(1, "%s %s SECURE_STOP:st_powerdown be interrupted\n", + tag, __func__); + } else { + logError(1, "%s %s SECURE_STOP:st_powerdown be completed\n", tag, __func__); + } + } + return OK; +} + +static void fts_secure_work(struct fts_secure_info *scr_info) +{ + struct fts_ts_info *info = (struct fts_ts_info *)scr_info->fts_info; + + + fts_secure_touch_notify(info); + atomic_set(&scr_info->st_1st_complete, 1); + if (wait_for_completion_interruptible(&scr_info->st_irq_processed) == -ERESTARTSYS) { + logError(1, "%s %s SECURE_FILTER:st_irq_processed be interrupted\n", tag, __func__); + } else { + logError(1, "%s %s SECURE_FILTER:st_irq_processed be completed\n", tag, __func__); + } + + fts_enableInterrupt(); + logError(1, "%s %s SECURE_FILTER:enable irq\n", tag, __func__); +} + +static void fts_flush_delay_task(struct fts_secure_info *scr_info) +{ + if (scr_info->scr_delay.palm_pending) { + scr_info->scr_delay.palm_pending = false; + } +} + +static int fts_secure_filter_interrupt(struct fts_ts_info *info) +{ + struct fts_secure_info *scr_info = info->secure_info; + + /*inited and enable first*/ + if (!scr_info->secure_inited || atomic_read(&scr_info->st_enabled) == 0) { + return -EPERM; + } + + fts_disableInterruptNoSync(); + logError(1, "%s %s SECURE_FILTER:disable irq\n", tag, __func__); + /*check and change irq pending state + *change irq pending here, secure_touch_show, secure_touch_enable_store + *completion st_irq_processed at secure_touch_show, secure_touch_enable_stroe + */ + logError(1, "%s %s SECURE_FILTER:st_pending_irqs = %d\n", + tag, __func__, atomic_read(&scr_info->st_pending_irqs)); + if (atomic_cmpxchg(&scr_info->st_pending_irqs, 0, 1) == 0) { + fts_secure_work(scr_info); + logError(1, "%s %s SECURE_FILTER:secure_work return\n", tag, __func__); + } + + return 0; +} + +static ssize_t fts_secure_touch_enable_show (struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + struct fts_secure_info *scr_info = info->secure_info; + + logError(1, "%s %s SECURE_TOUCH_ENABLE[R]:st_enabled = %d\n", tag, __func__, atomic_read(&scr_info->st_enabled)); + return scnprintf(buf, PAGE_SIZE, "%d", atomic_read(&scr_info->st_enabled)); +} + +/* echo 0 > secure_touch_enable to disable secure touch + * echo 1 > secure_touch_enable to enable secure touch + */ +static ssize_t fts_secure_touch_enable_store (struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int ret; + unsigned long value; + struct fts_ts_info *info = dev_get_drvdata(dev); + struct fts_secure_info *scr_info = info->secure_info; + + atomic_set(&scr_info->st_1st_complete, 0); + logError(1, "%s %s SECURE_TOUCH_ENABLE[W]:st_1st_complete=0\n", tag, __func__); + logError(1, "%s %s SECURE_TOUCH_ENABLE[W]:parse parameter\n", tag, __func__); + /*check and get cmd*/ + if (count > 2) + return -EINVAL; + ret = kstrtoul(buf, 10, &value); + if (ret != 0) + return ret; + + if (!scr_info->secure_inited) + return -EIO; + + ret = count; + + logError(1, "%s %s SECURE_TOUCH_ENABLE[W]:st_enabled = %d\n", tag, __func__, value); + switch (value) { + case 0: + if (atomic_read(&scr_info->st_enabled) == 0) { + logError(1, "%s %s secure touch is already disabled\n", + tag, __func__); + return ret; + } + mutex_lock(&scr_info->palm_lock); + atomic_set(&scr_info->st_enabled, 0); + fts_secure_touch_notify(info); + complete(&scr_info->st_irq_processed); + fts_event_handler(info->client->irq, info); + complete(&scr_info->st_powerdown); + fts_flush_delay_task(scr_info); + mutex_unlock(&scr_info->palm_lock); + logError(1, "%s %s SECURE_TOUCH_ENABLE[W]:disable secure touch successful\n", + tag, __func__); + break; + case 1: + if (atomic_read(&scr_info->st_enabled) == 1) { + logError(1, "%s %s secure touch is already enabled\n", + tag, __func__); + return ret; + } + mutex_lock(&scr_info->palm_lock); + /*wait until finish process all normal irq*/ + synchronize_irq(info->client->irq); + + /*enable secure touch*/ + reinit_completion(&scr_info->st_powerdown); + reinit_completion(&scr_info->st_irq_processed); + atomic_set(&scr_info->st_pending_irqs, 0); + atomic_set(&scr_info->st_enabled, 1); + mutex_unlock(&scr_info->palm_lock); + logError(1, "%s %s SECURE_TOUCH_ENABLE[W]:enable secure touch successful\n", + tag, __func__); + break; + default: + logError(1, "%s %s %d in secure_touch_enable is not support\n", + tag, __func__, value); + break; + } + return ret; +} + +static ssize_t fts_secure_touch_show (struct device *dev, struct device_attribute *attr, char *buf) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + struct fts_secure_info *scr_info = info->secure_info; + int value = 0; + + logError(1, "%s %s SECURE_TOUCH[R]:st_1st_complete = %d\n", + tag, __func__, atomic_read(&scr_info->st_1st_complete)); + logError(1, "%s %s SECURE_TOUCH[R]:st_pending_irqs = %d\n", + tag, __func__, atomic_read(&scr_info->st_pending_irqs)); + + if (atomic_read(&scr_info->st_enabled) == 0) { + return -EBADF; + } + + if (atomic_cmpxchg(&scr_info->st_pending_irqs, -1, 0) == -1) + return -EINVAL; + + if (atomic_cmpxchg(&scr_info->st_pending_irqs, 1, 0) == 1) { + value = 1; + } else if (atomic_cmpxchg(&scr_info->st_1st_complete, 1, 0) == 1) { + complete(&scr_info->st_irq_processed); + logError(1, "%s %s SECURE_TOUCH[R]:comlpetion st_irq_processed\n", tag, __func__); + } + return scnprintf(buf, PAGE_SIZE, "%d", value); +} +#endif +static DEVICE_ATTR(fts_lockdown, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_lockdown_show, fts_lockdown_store); +static DEVICE_ATTR(fwupdate, (S_IRUGO | S_IWUSR | S_IWGRP), fts_fwupdate_show, + fts_fwupdate_store); +static DEVICE_ATTR(panel_vendor, (S_IRUGO), fts_panel_vendor_show, NULL); +static DEVICE_ATTR(panel_color, (S_IRUGO), fts_panel_color_show, NULL); +static DEVICE_ATTR(panel_display, (S_IRUGO), fts_panel_display_show, NULL); +static DEVICE_ATTR(ms_strength, (S_IRUGO), fts_strength_frame_show, NULL); +static DEVICE_ATTR(lockdown_info, (S_IRUGO), fts_lockdown_info_show, NULL); +static DEVICE_ATTR(appid, (S_IRUGO), fts_appid_show, NULL); +static DEVICE_ATTR(mode_active, (S_IRUGO), fts_mode_active_show, NULL); +static DEVICE_ATTR(fw_file_test, (S_IRUGO), fts_fw_test_show, NULL); +static DEVICE_ATTR(selftest_info, (S_IRUGO), fts_selftest_info_show, NULL); +static DEVICE_ATTR(ms_raw, (S_IRUGO), fts_ms_raw_show, NULL); +static DEVICE_ATTR(ss_raw, (S_IRUGO), fts_ss_raw_show, NULL); +static DEVICE_ATTR(ms_cx_total, (S_IRUGO), fts_ms_cx_total_show, NULL); +static DEVICE_ATTR(ss_ix_total, (S_IRUGO), fts_ss_ix_total_show, NULL); +static DEVICE_ATTR(ss_hover, (S_IRUGO), fts_hover_raw_show, NULL); +static DEVICE_ATTR(stm_fts_cmd, (S_IRUGO | S_IWUSR | S_IWGRP), stm_fts_cmd_show, + stm_fts_cmd_store); +#ifdef USE_ONE_FILE_NODE +static DEVICE_ATTR(feature_enable, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_feature_enable_show, fts_feature_enable_store); +#else + +#ifdef GRIP_MODE +static DEVICE_ATTR(grip_mode, (S_IRUGO | S_IWUSR | S_IWGRP), fts_grip_mode_show, + fts_grip_mode_store); +#endif + +#ifdef CHARGER_MODE +static DEVICE_ATTR(charger_mode, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_charger_mode_show, fts_charger_mode_store); +#endif + +#ifdef GLOVE_MODE +static DEVICE_ATTR(glove_mode, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_glove_mode_show, fts_glove_mode_store); +#endif + +#ifdef COVER_MODE +static DEVICE_ATTR(cover_mode, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_cover_mode_show, fts_cover_mode_store); +#endif + +#ifdef STYLUS_MODE +static DEVICE_ATTR(stylus_mode, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_stylus_mode_show, fts_stylus_mode_store); +#endif + +#endif + +#ifdef GESTURE_MODE +static DEVICE_ATTR(gesture_mask, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_gesture_mask_show, fts_gesture_mask_store); +static DEVICE_ATTR(gesture_coordinates, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_gesture_coordinates_show, NULL); +#endif +static DEVICE_ATTR(doze_time, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_doze_time_show, fts_doze_time_store); +static DEVICE_ATTR(grip_enable, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_grip_enable_show, fts_grip_enable_store); +static DEVICE_ATTR(grip_area, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_grip_area_show, fts_grip_area_store); + +static DEVICE_ATTR(hover_tune, (S_IRUGO | S_IWUSR | S_IWGRP), NULL, fts_hover_autotune_store); + +static struct attribute *fts_attr_group[] = { + &dev_attr_fwupdate.attr, + &dev_attr_appid.attr, + &dev_attr_mode_active.attr, + &dev_attr_fw_file_test.attr, + &dev_attr_stm_fts_cmd.attr, +#ifdef USE_ONE_FILE_NODE + &dev_attr_feature_enable.attr, +#else + +#ifdef GRIP_MODE + &dev_attr_grip_mode.attr, +#endif +#ifdef CHARGER_MODE + &dev_attr_charger_mode.attr, +#endif +#ifdef GLOVE_MODE + &dev_attr_glove_mode.attr, +#endif +#ifdef COVER_MODE + &dev_attr_cover_mode.attr, +#endif +#ifdef STYLUS_MODE + &dev_attr_stylus_mode.attr, +#endif +#endif + &dev_attr_fts_lockdown.attr, + &dev_attr_panel_vendor.attr, + &dev_attr_panel_color.attr, + &dev_attr_panel_display.attr, + &dev_attr_lockdown_info.attr, +#ifdef GESTURE_MODE + &dev_attr_gesture_mask.attr, + &dev_attr_gesture_coordinates.attr, +#endif + &dev_attr_selftest_info.attr, + &dev_attr_ms_raw.attr, + &dev_attr_ss_raw.attr, + &dev_attr_ms_cx_total.attr, + &dev_attr_ss_ix_total.attr, + &dev_attr_ms_strength.attr, + &dev_attr_ss_hover.attr, + &dev_attr_hover_tune.attr, + &dev_attr_doze_time.attr, + &dev_attr_grip_enable.attr, + &dev_attr_grip_area.attr, + NULL, +}; + +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP +static DEVICE_ATTR(touch_suspend_notify, (S_IRUGO | S_IRGRP), + fts_touch_suspend_notify_show, NULL); +#endif +#ifdef CONFIG_FTS_FOD_AREA_REPORT +static DEVICE_ATTR(fod_status, (S_IRUGO | S_IWUSR | S_IWGRP), + fts_fod_status_show, fts_fod_status_store); + +static DEVICE_ATTR(fod_test, (S_IRUGO | S_IWUSR | S_IWGRP), NULL, fts_fod_test_store); +#endif + +#ifdef CONFIG_SECURE_TOUCH +DEVICE_ATTR(secure_touch_enable, (S_IRUGO | S_IWUSR | S_IWGRP), fts_secure_touch_enable_show, fts_secure_touch_enable_store); +DEVICE_ATTR(secure_touch, (S_IRUGO | S_IWUSR | S_IWGRP), fts_secure_touch_show, NULL); +#endif +/**@}*/ +/**@}*/ + +/** + * @defgroup isr Interrupt Service Routine (Event Handler) + * The most important part of the driver is the ISR (Interrupt Service Routine) called also as Event Handler \n + * As soon as the interrupt pin goes low, fts_interrupt_handler() is called and the chain to read and parse the event read from the FIFO start.\n + * For any different kind of EVT_ID there is a specific event handler which will take the correct action to report the proper info to the host. \n + * The most important events are the one related to touch informations, status update or user report. + * @{ + */ + +/** + * Report to the linux input system the pressure and release of a button handling concurrency + * @param info pointer to fts_ts_info which contains info about the device and its hw setup + * @param key_code button value + */ +void fts_input_report_key(struct fts_ts_info *info, int key_code) +{ + mutex_lock(&info->input_report_mutex); + input_report_key(info->input_dev, key_code, 1); + input_sync(info->input_dev); + input_report_key(info->input_dev, key_code, 0); + input_sync(info->input_dev); + mutex_unlock(&info->input_report_mutex); +} + +/** +* Event Handler for no events (EVT_ID_NOEVENT) +*/ +static void fts_nop_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + logError(1, + "%s %s Doing nothing for event = %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); +} + +#ifdef CONFIG_FTS_FOD_AREA_REPORT +static bool fts_is_in_fodarea(int x, int y) +{ + if ((x > FOD_LX && x < FOD_LX + FOD_SIDE) && (y > FOD_LY && y < FOD_LY + + FOD_SIDE)) + return true; + else + return false; +} + +static bool finger_report_flag; + +#endif + +/** +* Event handler for enter and motion events (EVT_ID_ENTER_POINT, EVT_ID_MOTION_POINT ) +* report to the linux input system touches with their coordinated and additional informations +*/ +static void fts_enter_pointer_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + unsigned char touch_id = (event[1] & 0xF0) >> 4; + unsigned int tool = MT_TOOL_FINGER; + unsigned int is_touching = 1; + u8 touch_type = event[1] & 0x0F; + int area_size = 1; + int x = ((event[3] & 0x0F) << 8) | (event[2]); + int y = (event[4] << 4) | ((event[3] & 0xF0) >> 4); + + if (event[0] == EVT_ID_MOTION_POINT) + area_size = (event[5] << 8) | event[6]; + + if (x >= info->board->x_max) + x = info->board->x_max; + + if (y >= info->board->y_max) + y = info->board->y_max; + + switch (touch_type) { +#ifdef STYLUS_MODE + case TOUCH_TYPE_STYLUS: + logError(0, "%s %s : It is a stylus!\n", tag, __func__); + if (info->stylus_enabled == 1) { + tool = MT_TOOL_PEN; + is_touching = 1; + __set_bit(touch_id, &info->stylus_id); + break; + } +#endif + case TOUCH_TYPE_FINGER: + case TOUCH_TYPE_GLOVE: + case TOUCH_TYPE_PALM: + tool = MT_TOOL_FINGER; + is_touching = 1; + __set_bit(touch_id, &info->touch_id); + break; + case TOUCH_TYPE_HOVER: + tool = MT_TOOL_FINGER; + is_touching = 0; + __set_bit(touch_id, &info->touch_id); + break; + + case TOUCH_TYPE_INVALID: + default: + logError(1, "%s %s : Invalid touch type = %d ! No Report...\n", + tag, __func__, touch_type); + return; + } + +#ifdef CONFIG_FTS_FOD_AREA_REPORT + if (info->fod_status && fts_is_in_fodarea(x, y)) { + info->fod_id = 0; + __set_bit(touch_id, &info->fod_id); + } else if (__test_and_clear_bit(touch_id, &info->fod_id)) { + input_report_key(info->input_dev, BTN_INFO, 0); + input_report_key(info->input_dev, KEY_INFO, 0); + input_sync(info->input_dev); + } +#endif + + input_mt_slot(info->input_dev, touch_id); + input_mt_report_slot_state(info->input_dev, tool, 1); + input_report_key(info->input_dev, BTN_TOUCH, is_touching); + if (is_touching) + input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); + + input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(info->input_dev, ABS_MT_DISTANCE, is_touching ? DISTANCE_MIN : DISTANCE_MAX); + input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, area_size); + + input_sync(info->input_dev); +} + +/** +* Event handler for leave event (EVT_ID_LEAVE_POINT ) +* Report to the linux input system that one touch left the display +*/ +static void fts_leave_pointer_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + unsigned int tool = MT_TOOL_FINGER; + unsigned int is_touching = 0; + unsigned char touch_id; + u8 touch_type; + +#ifdef CONFIG_FTS_FOD_AREA_REPORT + // Special leave event for the FOD in sleep case + if (event[1] == 0xb5) { + // If we don't have a valid FOD id, we don't have what to leave + // If we have other touch ids, we're not in sleep + if (!info->fod_id || info->touch_id) { + return; + } + + touch_id = ffs(info->fod_id) - 1; + touch_type = TOUCH_TYPE_FINGER; + } else { +#endif + touch_type = event[1] & 0x0F; + touch_id = (event[1] & 0xF0) >> 4; +#ifdef CONFIG_FTS_FOD_AREA_REPORT + } +#endif + + switch (touch_type) { +#ifdef STYLUS_MODE + case TOUCH_TYPE_STYLUS: + logError(0, "%s %s : It is a stylus!\n", tag, __func__); + if (info->stylus_enabled == 1) { + tool = MT_TOOL_PEN; + __clear_bit(touch_id, &info->stylus_id); + break; + } +#endif + case TOUCH_TYPE_FINGER: + case TOUCH_TYPE_GLOVE: + case TOUCH_TYPE_PALM: + tool = MT_TOOL_FINGER; + is_touching = 1; + __clear_bit(touch_id, &info->touch_id); + break; + case TOUCH_TYPE_HOVER: + tool = MT_TOOL_FINGER; + is_touching = 0; + __clear_bit(touch_id, &info->touch_id); + break; + case TOUCH_TYPE_INVALID: + default: + logError(1, "%s %s : Invalid touch type = %d ! No Report...\n", + tag, __func__, touch_type); + return; + } + +#ifdef CONFIG_FTS_FOD_AREA_REPORT + if (__test_and_clear_bit(touch_id, &info->fod_id)) { + input_report_key(info->input_dev, BTN_INFO, 0); + input_report_key(info->input_dev, KEY_INFO, 0); + input_sync(info->input_dev); + } +#endif + + input_mt_slot(info->input_dev, touch_id); + input_mt_report_slot_state(info->input_dev, tool, 0); + if (!info->touch_id) { + input_report_key(info->input_dev, BTN_TOUCH, 0); + if (is_touching) + input_report_key(info->input_dev, BTN_TOOL_FINGER, 0); + } + input_sync(info->input_dev); +} + +/* EventId : EVT_ID_MOTION_POINT */ +#define fts_motion_pointer_event_handler fts_enter_pointer_event_handler + +/** +* Event handler for error events (EVT_ID_ERROR) +* Handle unexpected error events implementing recovery strategy and restoring the sensing status that the IC had before the error occured +*/ +static void fts_error_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + int error = 0; + logError(1, + "%s %s Received event %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); + + switch (event[1]) { + case EVT_TYPE_ERROR_ESD: + { + release_all_touches(info); + + fts_chip_powercycle(info); + + error = fts_system_reset(); + error |= fts_mode_handler(info, 0); + error |= fts_enableInterrupt(); + if (error < OK) { + logError(1, + "%s %s Cannot restore the device ERROR %08X\n", + tag, __func__, error); + } + } + break; + case EVT_TYPE_ERROR_WATCHDOG: + { + dumpErrorInfo(NULL, 0); + release_all_touches(info); + error = fts_system_reset(); + error |= fts_mode_handler(info, 0); + error |= fts_enableInterrupt(); + if (error < OK) { + logError(1, + "%s %s Cannot reset the device ERROR %08X\n", + tag, __func__, error); + } + } + break; + + } +} + +/** +* Event handler for controller ready event (EVT_ID_CONTROLLER_READY) +* Handle controller events received after unexpected reset of the IC updating the resets flag and restoring the proper sensing status +*/ +static void fts_controller_ready_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + int error; + logError(1, + "%s %s Received event %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); + release_all_touches(info); + setSystemResetedUp(1); + setSystemResetedDown(1); + error = fts_mode_handler(info, 0); + if (error < OK) { + logError(1, + "%s %s Cannot restore the device status ERROR %08X\n", + tag, __func__, error); + } +} + +/** +* Event handler for status events (EVT_ID_STATUS_UPDATE) +* Handle status update events +*/ +static void fts_status_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + switch (event[1]) { + + case EVT_TYPE_STATUS_ECHO: + logError(0, + "%s %s Echo event of command = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], event[5], + event[6], event[7]); + break; + + case EVT_TYPE_STATUS_FORCE_CAL: + switch (event[2]) { + case 0x00: + logError(1, + "%s %s Continuous frame drop Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x01: + logError(1, + "%s %s Mutual negative detect Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x02: + logError(1, + "%s %s Mutual calib deviation Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x11: + logError(1, + "%s %s SS negative detect Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x12: + logError(1, + "%s %s SS negative detect Force cal in Low Power mode = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x13: + logError(1, + "%s %s SS negative detect Force cal in Idle mode = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x20: + logError(1, + "%s %s SS invalid Mutual Strength soft Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x21: + logError(1, + "%s %s SS invalid Self Strength soft Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x22: + logError(1, + "%s %s SS invalid Self Island soft Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x30: + logError(1, + "%s %s MS invalid Mutual Strength soft Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x31: + logError(1, + "%s %s MS invalid Self Strength soft Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + default: + logError(1, + "%s %s Force cal = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + + } + break; + + case EVT_TYPE_STATUS_FRAME_DROP: + switch (event[2]) { + case 0x01: + logError(1, + "%s %s Frame drop noisy frame = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x02: + logError(1, + "%s %s Frame drop bad R = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case 0x03: + logError(1, + "%s %s Frame drop invalid processing state = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + default: + logError(1, + "%s %s Frame drop = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + + } + break; + + case EVT_TYPE_STATUS_SS_RAW_SAT: + if (event[2] == 1) + logError(1, + "%s %s SS Raw Saturated = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + else + logError(1, + "%s %s SS Raw No more Saturated = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + + case EVT_TYPE_STATUS_WATER: + if (event[2] == 1) + logError(1, + "%s %s Enter Water mode = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + else + logError(1, + "%s %s Exit Water mode = %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[2], event[3], event[4], + event[5], event[6], event[7]); + break; + default: + logError(1, + "%s %s Received unhandled status event = %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); + break; + } + +} + +#ifdef PHONE_KEY +/** + * Event handler for status events (EVT_TYPE_USER_KEY) + * Handle keys update events, the third byte of the event is a bitmask where if the bit set means that the corresponding key is pressed. + */ +static void fts_key_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + + logError(0, + "%s %s Received event %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); + + if (event[0] == EVT_ID_USER_REPORT && event[1] == EVT_TYPE_USER_KEY) { + + if ((event[2] & FTS_KEY_0) == 0 && (key_mask & FTS_KEY_0) > 0) { + logError(0, + "%s %s: Button HOME pressed and released! \n", + tag, __func__); + fts_input_report_key(info, KEY_HOMEPAGE); + } + + if ((event[2] & FTS_KEY_1) == 0 && (key_mask & FTS_KEY_1) > 0) { + logError(0, + "%s %s: Button Back pressed and released! \n", + tag, __func__); + fts_input_report_key(info, KEY_BACK); + } + + if ((event[2] & FTS_KEY_2) == 0 && (key_mask & FTS_KEY_2) > 0) { + logError(0, "%s %s: Button Menu pressed! \n", tag, + __func__); + fts_input_report_key(info, KEY_MENU); + } + + key_mask = event[2]; + } else { + logError(1, "%s %s: Invalid event passed as argument! \n", tag, + __func__); + } + +} +#endif + +#ifdef GESTURE_MODE +/** + * Event handler for gesture events (EVT_TYPE_USER_GESTURE) + * Handle gesture events and simulate the click on a different button for any gesture detected (@link gesture_opt Gesture IDs @endlink) + */ +static void fts_gesture_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + bool get_coords = true; + int value; + +#ifdef CONFIG_FTS_FOD_AREA_REPORT + int area_size = (event[9] << 8) | (event[8]); + int x = (event[4] << 8) | (event[3]); + int y = (event[6] << 8) | (event[5]); +#endif + + if (event[0] != EVT_ID_USER_REPORT || event[1] != EVT_TYPE_USER_GESTURE) + return; + +#ifdef CONFIG_FTS_FOD_AREA_REPORT + if (info->fod_status && event[2] == GEST_ID_LONG_PRESS) { + if (fts_is_in_fodarea(x, y)) { + input_report_key(info->input_dev, BTN_INFO, 1); + input_report_key(info->input_dev, KEY_INFO, 1); + input_sync(info->input_dev); + + // Active mode, the touch has already been reported + if (info->fod_id) + return; + + // Sleep mode, report a touch and set a FOD id + __set_bit(0, &info->fod_id); + input_mt_slot(info->input_dev, 0); + input_mt_report_slot_state(info->input_dev, MT_TOOL_FINGER, 1); + input_report_key(info->input_dev, BTN_TOUCH, 1); + input_report_key(info->input_dev, BTN_TOOL_FINGER, 1); + input_report_abs(info->input_dev, ABS_MT_POSITION_X, x); + input_report_abs(info->input_dev, ABS_MT_POSITION_Y, y); + input_report_abs(info->input_dev, ABS_MT_DISTANCE, DISTANCE_MIN); + input_report_abs(info->input_dev, ABS_MT_TOUCH_MAJOR, area_size); + input_sync(info->input_dev); + } + + return; + } else if (info->fod_status && event[2] == GEST_ID_SINGTAP) { + input_report_key(info->input_dev, KEY_GOTO, 1); + input_sync(info->input_dev); + input_report_key(info->input_dev, KEY_GOTO, 0); + input_sync(info->input_dev); + + return; + } +#endif + + if (!info->gesture_enabled) + return; + + switch (event[2]) { + case GEST_ID_DBLTAP: + value = KEY_WAKEUP; + logError(0, "%s %s: double tap ! \n", tag, __func__); + get_coords = 0; + break; + + case GEST_ID_AT: + value = KEY_WWW; + logError(0, "%s %s: @ ! \n", tag, __func__); + break; + + case GEST_ID_C: + value = KEY_C; + logError(0, "%s %s: C ! \n", tag, __func__); + break; + + case GEST_ID_E: + value = KEY_E; + logError(0, "%s %s: e ! \n", tag, __func__); + break; + + case GEST_ID_F: + value = KEY_F; + logError(0, "%s %s: F ! \n", tag, __func__); + break; + + case GEST_ID_L: + value = KEY_L; + logError(0, "%s %s: L ! \n", tag, __func__); + break; + + case GEST_ID_M: + value = KEY_M; + logError(0, "%s %s: M ! \n", tag, __func__); + break; + + case GEST_ID_O: + value = KEY_O; + logError(0, "%s %s: O ! \n", tag, __func__); + break; + + case GEST_ID_S: + value = KEY_S; + logError(0, "%s %s: S ! \n", tag, __func__); + break; + + case GEST_ID_V: + value = KEY_V; + logError(0, "%s %s: V ! \n", tag, __func__); + break; + + case GEST_ID_W: + value = KEY_W; + logError(0, "%s %s: W ! \n", tag, __func__); + break; + + case GEST_ID_Z: + value = KEY_Z; + logError(0, "%s %s: Z ! \n", tag, __func__); + break; + + case GEST_ID_RIGHT_1F: + value = KEY_RIGHT; + logError(0, "%s %s: -> ! \n", tag, __func__); + break; + + case GEST_ID_LEFT_1F: + value = KEY_LEFT; + logError(0, "%s %s: <- ! \n", tag, __func__); + break; + + case GEST_ID_UP_1F: + value = KEY_UP; + logError(0, "%s %s: UP ! \n", tag, __func__); + break; + + case GEST_ID_DOWN_1F: + value = KEY_DOWN; + logError(0, "%s %s: DOWN ! \n", tag, __func__); + break; + + case GEST_ID_CARET: + value = KEY_APOSTROPHE; + logError(0, "%s %s: ^ ! \n", tag, __func__); + break; + + case GEST_ID_LEFTBRACE: + value = KEY_LEFTBRACE; + logError(0, "%s %s: < ! \n", tag, __func__); + break; + + case GEST_ID_RIGHTBRACE: + value = KEY_RIGHTBRACE; + logError(0, "%s %s: > ! \n", tag, __func__); + break; + + default: + logError(0, "%s %s: No valid GestureID! \n", tag, + __func__); + return; + + } + + if (get_coords == 1) + readGestureCoords(event); + + fts_input_report_key(info, value); +} +#endif + +/** + * Event handler for user report events (EVT_ID_USER_REPORT) + * Handle user events reported by the FW due to some interaction triggered by an external user (press keys, perform gestures, etc.) + */ +static void fts_user_report_event_handler(struct fts_ts_info *info, + unsigned char *event) +{ + + switch (event[1]) { + +#ifdef PHONE_KEY + case EVT_TYPE_USER_KEY: + fts_key_event_handler(info, event); + break; +#endif + + case EVT_TYPE_USER_PROXIMITY: + if (event[2] == 0) { + logError(1, "%s %s No proximity!\n", tag, __func__); + } else { + logError(1, "%s %s Proximity Detected!\n", tag, + __func__); + } + break; + +#ifdef GESTURE_MODE + case EVT_TYPE_USER_GESTURE: + fts_gesture_event_handler(info, event); + break; +#endif + default: + logError(1, + "%s %s Received unhandled user report event = %02X %02X %02X %02X %02X %02X %02X %02X\n", + tag, __func__, event[0], event[1], event[2], event[3], + event[4], event[5], event[6], event[7]); + break; + } + +} + +/* +static void buffDump(unsigned char *buf, unsigned int buflength, char *tag) +{ + unsigned char *tmp, *back; + unsigned int i; + unsigned int to_read; + unsigned int remain = buflength; + unsigned int chunk = 10; + + logError(1, "%s BUFFDUMP IN:", tag); + + tmp = kmalloc(300, GFP_ATOMIC); + if (!tmp) { + logError(1, "alloc tmp=%04d byte failed", 300); + return; + } + back = tmp; + + memcpy(tmp, buf, buflength); + + while (remain > 0) { + if (remain > chunk) { + remain -= chunk; + to_read = chunk; + } else { + to_read = remain; + for (i = to_read; i < chunk; i++) { + tmp[i] = 0xED; + } + remain = 0; + } + + logError(1, "%s %02x %02x %02x %02x %02x %02x %02x %02x %02x %02x", + tag, tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5], tmp[6], tmp[7], tmp[8], tmp[9]); + + tmp += to_read; + } + kfree(back); +} +*/ + +static void fts_ts_sleep_work(struct work_struct *work) +{ + struct fts_ts_info *info = container_of(work, struct fts_ts_info, sleep_work); + int error = 0, count = 0; + unsigned char regAdd = FIFO_CMD_READALL; + unsigned char data[FIFO_EVENT_SIZE * FIFO_DEPTH] = {0}; + unsigned char eventId; + const unsigned char EVENTS_REMAINING_POS = 7; + const unsigned char EVENTS_REMAINING_MASK = 0x1F; + unsigned char events_remaining = 0; + unsigned char *evt_data; + static char pre_id[3]; + event_dispatch_handler_t event_handler; + int r; + fts_disableInterrupt(); + if (info->tp_pm_suspend) { + r = wait_for_completion_timeout(&info->pm_resume_completion, msecs_to_jiffies(500)); + if (!r) { + logError(1, "%s pm_resume_completion timeout, i2c is closed", tag); + pm_relax(info->dev); + fts_enableInterrupt(); + return; + } else { + logError(1, "%s pm_resume_completion be completed, handling irq", tag); + } + } + + info->irq_status = true; + error = fts_writeReadU8UX(regAdd, 0, 0, data, FIFO_EVENT_SIZE, + DUMMY_FIFO); + events_remaining = data[EVENTS_REMAINING_POS] & EVENTS_REMAINING_MASK; + events_remaining = (events_remaining > FIFO_DEPTH - 1) ? + FIFO_DEPTH - 1 : events_remaining; + + /*Drain the rest of the FIFO, up to 31 events*/ + if (error == OK && events_remaining > 0) { + error = fts_writeReadU8UX(regAdd, 0, 0, &data[FIFO_EVENT_SIZE], + FIFO_EVENT_SIZE * events_remaining, + DUMMY_FIFO); + } + if (error != OK) { + logError(1, + "Error (%d) while reading from FIFO in fts_event_handler", + error); + } else { + for (count = 0; count < events_remaining + 1; count++) { + evt_data = &data[count * FIFO_EVENT_SIZE]; + if (pre_id[0] == EVT_ID_USER_REPORT && + pre_id[1] == 0x02 && + pre_id[2] == 0x18) { + pre_id[0] = 0; + pre_id[1] = 0; + pre_id[2] = 0; + continue; + } + if (evt_data[0] == EVT_ID_NOEVENT) + break; + eventId = evt_data[0] >> 4; + /*Ensure event ID is within bounds*/ + if (eventId < NUM_EVT_ID) { + event_handler = info->event_dispatch_table[eventId]; + event_handler(info, (evt_data)); + pre_id[0] = evt_data[0]; + pre_id[1] = evt_data[1]; + pre_id[2] = evt_data[2]; + } + } + } + input_sync(info->input_dev); + info->irq_status = false; + pm_relax(info->dev); + fts_enableInterrupt(); + return; +} + +/** + * Bottom Half Interrupt Handler function + * This handler is called each time there is at least one new event in the FIFO and the interrupt pin of the IC goes low. + * It will read all the events from the FIFO and dispatch them to the proper event handler according the event ID + */ +static irqreturn_t fts_event_handler(int irq, void *ts_info) +{ + struct fts_ts_info *info = ts_info; + int error = 0, count = 0; + unsigned char regAdd = FIFO_CMD_READALL; + unsigned char data[FIFO_EVENT_SIZE * FIFO_DEPTH] = {0}; + unsigned char eventId; + const unsigned char EVENTS_REMAINING_POS = 7; + const unsigned char EVENTS_REMAINING_MASK = 0x1F; + unsigned char events_remaining = 0; + unsigned char *evt_data; + static char pre_id[3]; + event_dispatch_handler_t event_handler; + + if (info->tp_pm_suspend) { + logError(1, "%s device in suspend, schedue to work", tag); + pm_wakeup_event(info->dev, 0); + if (!work_pending(&info->sleep_work)) { + pm_stay_awake(info->dev); + queue_work(info->irq_wq, &info->sleep_work); + } + return IRQ_HANDLED; + } + +#ifdef CONFIG_SECURE_TOUCH + if (!fts_secure_filter_interrupt(info)) { + return IRQ_HANDLED; + } +#endif + + info->irq_status = true; + error = fts_writeReadU8UX(regAdd, 0, 0, data, FIFO_EVENT_SIZE, + DUMMY_FIFO); + events_remaining = data[EVENTS_REMAINING_POS] & EVENTS_REMAINING_MASK; + events_remaining = (events_remaining > FIFO_DEPTH - 1) ? + FIFO_DEPTH - 1 : events_remaining; + + /*Drain the rest of the FIFO, up to 31 events*/ + if (error == OK && events_remaining > 0) { + error = fts_writeReadU8UX(regAdd, 0, 0, &data[FIFO_EVENT_SIZE], + FIFO_EVENT_SIZE * events_remaining, + DUMMY_FIFO); + } + if (error != OK) { + logError(1, + "Error (%d) while reading from FIFO in fts_event_handler", + error); + } else { + for (count = 0; count < events_remaining + 1; count++) { + evt_data = &data[count * FIFO_EVENT_SIZE]; + if (pre_id[0] == EVT_ID_USER_REPORT && + pre_id[1] == 0x02 && + pre_id[2] == 0x18) { + pre_id[0] = 0; + pre_id[1] = 0; + pre_id[2] = 0; + continue; + } + if (evt_data[0] == EVT_ID_NOEVENT) + break; + eventId = evt_data[0] >> 4; + /*Ensure event ID is within bounds*/ + if (eventId < NUM_EVT_ID) { + event_handler = info->event_dispatch_table[eventId]; + event_handler(info, (evt_data)); + pre_id[0] = evt_data[0]; + pre_id[1] = evt_data[1]; + pre_id[2] = evt_data[2]; + } + } + } + input_sync(info->input_dev); + info->irq_status = false; + return IRQ_HANDLED; +} + +/**@}*/ + +static const char *fts_get_config(struct fts_ts_info *info) +{ + struct fts_hw_platform_data *pdata = info->board; + int i = 0, ret = 0; + + ret = fts_get_lockdown_info(info->lockdown_info, info); + + if (ret < OK) { + logError(1, "%s can't read lockdown info", tag); + return pdata->default_fw_name; + } + + ret |= fts_enableInterrupt(); + + for (i = 0; i < pdata->config_array_size; i++) { + if (info->lockdown_info[0] == pdata->config_array[i].tp_vendor) + break; + } + + if (i >= pdata->config_array_size) { + logError(1, "%s can't find right config", tag); + return pdata->default_fw_name; + } + + logError(1, "%s Choose config %d: %s", tag, i, + pdata->config_array[i].fts_cfg_name); + pdata->current_index = i; +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + if (pdata->dump_click_count) { + info->current_clicknum_file = + kzalloc(TOUCH_COUNT_FILE_MAXSIZE, GFP_KERNEL); + strlcpy(info->current_clicknum_file, + pdata->config_array[i].clicknum_file_name, + TOUCH_COUNT_FILE_MAXSIZE); + } +#endif + return pdata->config_array[i].fts_cfg_name; +} + +static const char *fts_get_limit(struct fts_ts_info *info) +{ + struct fts_hw_platform_data *pdata = info->board; + int i = 0, ret = 0; + + ret = fts_get_lockdown_info(info->lockdown_info, info); + + if (ret < OK) { + logError(1, "%s can't read lockdown info", tag); + return LIMITS_FILE; + } + + ret |= fts_enableInterrupt(); + + for (i = 0; i < pdata->config_array_size; i++) { + if (info->lockdown_info[0] == pdata->config_array[i].tp_vendor) + break; + } + + if (i >= pdata->config_array_size) { + logError(1, "%s can't find right limit", tag); + return LIMITS_FILE; + } + + logError(1, "%s Choose limit file %d: %s", tag, i, + pdata->config_array[i].fts_limit_name); + pdata->current_index = i; + return pdata->config_array[i].fts_limit_name; +} + +/** +* Implement the fw update and initialization flow of the IC that should be executed at every boot up. +* The function perform a fw update of the IC in case of crc error or a new fw version and then understand if the IC need to be re-initialized again. +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_fw_update(struct fts_ts_info *info, const char *fw_name, int force) +{ + + u8 error_to_search[4] = {EVT_TYPE_ERROR_CRC_CX_HEAD, EVT_TYPE_ERROR_CRC_CX, + EVT_TYPE_ERROR_CRC_CX_SUB_HEAD, EVT_TYPE_ERROR_CRC_CX_SUB + }; + int retval = 0; + int retval1 = 0; + int ret; + int crc_status = 0; + int error = 0; + int init_type = NO_INIT; +#ifdef PRE_SAVED_METHOD + int keep_cx = 1; +#else + int keep_cx = 0; +#endif + + logError(1, "%s Fw Auto Update is starting... \n", tag); + + ret = fts_crc_check(); + if (ret > OK) { + logError(1, "%s %s: CRC Error or NO FW!\n", tag, __func__); + crc_status = ret; + } else { + crc_status = 0; + logError(1, + "%s %s: NO CRC Error or Impossible to read CRC register! \n", + tag, __func__); + } + + if (fw_name == NULL) { + fw_name = fts_get_config(info); + if (fw_name == NULL) + logError(1, "%s not found mached config!", tag); + } + + if (fw_name) { + if (force) + retval = flashProcedure(fw_name, 1, keep_cx); + else + retval = flashProcedure(fw_name, crc_status, keep_cx); + + if ((retval & 0xFF000000) == ERROR_FLASH_PROCEDURE) { + logError(1, + "%s %s: firmware update failed and retry! ERROR %08X\n", + tag, __func__, retval); + fts_chip_powercycle(info); + retval1 = flashProcedure(info->board->default_fw_name, crc_status, keep_cx); + if ((retval1 & 0xFF000000) == ERROR_FLASH_PROCEDURE) { + logError(1, + "%s %s: firmware update failed again! ERROR %08X\n", + tag, __func__, retval1); + logError(1, "%s Fw Auto Update Failed!\n", tag); + } + } + } + + logError(1, "%s %s: Verifying if CX CRC Error...\n", tag, __func__, + ret); + ret = fts_system_reset(); + if (ret >= OK) { + ret = pollForErrorType(error_to_search, 4); + if (ret < OK) { + logError(1, "%s %s: No Cx CRC Error Found! \n", tag, + __func__); + logError(1, "%s %s: Verifying if Panel CRC Error... \n", + tag, __func__); + error_to_search[0] = EVT_TYPE_ERROR_CRC_PANEL_HEAD; + error_to_search[1] = EVT_TYPE_ERROR_CRC_PANEL; + ret = pollForErrorType(error_to_search, 2); + if (ret < OK) { + logError(1, + "%s %s: No Panel CRC Error Found! \n", + tag, __func__); + init_type = NO_INIT; + } else { + logError(1, + "%s %s: Panel CRC Error FOUND! CRC ERROR = %02X\n", + tag, __func__, ret); + init_type = SPECIAL_PANEL_INIT; + } + } else { + logError(1, + "%s %s: Cx CRC Error FOUND! CRC ERROR = %02X\n", + tag, __func__, ret); + + logError(1, + "%s %s: Try to recovery with CX in fw file...\n", + tag, __func__, ret); + flashProcedure(info->board->default_fw_name, CRC_CX, 0); + logError(1, "%s %s: Refresh panel init data... \n", tag, + __func__, ret); + } + } else { + logError(1, + "%s %s: Error while executing system reset! ERROR %08X\n", + tag, __func__, ret); + } + + if (init_type == NO_INIT) { +#ifdef PRE_SAVED_METHOD + if (systemInfo.u8_cfgAfeVer != systemInfo.u8_cxAfeVer) { + init_type = SPECIAL_FULL_PANEL_INIT; + logError(0, + "%s %s: Different CX AFE Ver: %02X != %02X... Execute FULL Panel Init! \n", + tag, __func__, systemInfo.u8_cfgAfeVer, + systemInfo.u8_cxAfeVer); + } else +#endif + + if (systemInfo.u8_cfgAfeVer != systemInfo.u8_panelCfgAfeVer) { + init_type = SPECIAL_PANEL_INIT; + logError(0, + "%s %s: Different Panel AFE Ver: %02X != %02X... Execute Panel Init! \n", + tag, __func__, systemInfo.u8_cfgAfeVer, + systemInfo.u8_panelCfgAfeVer); + } else { + init_type = NO_INIT; + } + } + + if (init_type != NO_INIT) { + error = fts_chip_initialization(info, init_type); + if (error < OK) { + logError(1, + "%s %s Cannot initialize the chip ERROR %08X\n", + tag, __func__, error); + } + } + + error = fts_init_sensing(info); + if (error < OK) { + logError(1, + "%s Cannot initialize the hardware device ERROR %08X\n", + tag, error); + } + + logError(1, "%s Fw Update Finished! error = %08X\n", tag, error); + return error; +} + +#ifndef FW_UPDATE_ON_PROBE + +/** +* Function called by the delayed workthread executed after the probe in order to perform the fw update flow +* @see fts_fw_update() +*/ +static void fts_fw_update_auto(struct work_struct *work) +{ + struct delayed_work *fwu_work = + container_of(work, struct delayed_work, work); + struct fts_ts_info *info = + container_of(fwu_work, struct fts_ts_info, fwu_work); + fts_fw_update(info, NULL, 0); +} +#endif + +/** +* Execute the initialization of the IC (supporting a retry mechanism), checking also the resulting data +* @see production_test_main() +*/ +static int fts_chip_initialization(struct fts_ts_info *info, int init_type) +{ + int ret2 = 0; + int retry; + int initretrycnt = 0; + + for (retry = 0; retry <= RETRY_INIT_BOOT; retry++) { + ret2 = production_test_initialization(init_type); + if (ret2 == OK) + break; + initretrycnt++; + logError(1, + "%s initialization cycle count = %04d - ERROR %08X \n", + tag, initretrycnt, ret2); + fts_chip_powercycle(info); + } + + if (ret2 < OK) { + logError(1, "%s fts initialization failed 3 times \n", tag); + } + + return ret2; +} + +/** + * @addtogroup isr + * @{ + */ +/** +* Top half Interrupt handler function +* Respond to the interrupt and schedule the bottom half interrupt handler in its work queue +* @see fts_event_handler() +*/ +/* +static irqreturn_t fts_interrupt_handler(int irq, void *handle) +{ + struct fts_ts_info *info = handle; +#ifdef CONFIG_SECURE_TOUCH + if (!fts_secure_filter_interrupt(info)) { + return IRQ_HANDLED; + } +#endif + disable_irq_nosync(info->client->irq); + queue_work(info->event_wq, &info->work); + + return IRQ_HANDLED; +} +*/ +/** +* Initialize the dispatch table with the event handlers for any possible event ID and the interrupt routine behavior (triggered when the IRQ pin is low and associating the top half interrupt handler function). +* @see fts_interrupt_handler() +*/ +static int fts_interrupt_install(struct fts_ts_info *info) +{ + int i, error = 0; + + info->event_dispatch_table = + kzalloc(sizeof(event_dispatch_handler_t) * NUM_EVT_ID, GFP_KERNEL); + + if (!info->event_dispatch_table) { + logError(1, "%s OOM allocating event dispatch table\n", tag); + return -ENOMEM; + } + + for (i = 0; i < NUM_EVT_ID; i++) + info->event_dispatch_table[i] = fts_nop_event_handler; + + install_handler(info, ENTER_POINT, enter_pointer); + install_handler(info, LEAVE_POINT, leave_pointer); + install_handler(info, MOTION_POINT, motion_pointer); + install_handler(info, ERROR, error); + install_handler(info, CONTROLLER_READY, controller_ready); + install_handler(info, STATUS_UPDATE, status); + install_handler(info, USER_REPORT, user_report); + + /* disable interrupts in any case */ + error = fts_disableInterrupt(); + logError(1, "%s Interrupt Mode\n", tag); + if (request_threaded_irq(info->client->irq, NULL, fts_event_handler, info->board->irq_flags, + FTS_TS_DRV_NAME, info)) { + logError(1, "%s Request irq failed\n", tag); + kfree(info->event_dispatch_table); + error = -EBUSY; + } else { + disable_irq(info->client->irq); + } + + return error; +} + +/** +* Clean the dispatch table and the free the IRQ. +* This function is called when the driver need to be removed +*/ +static void fts_interrupt_uninstall(struct fts_ts_info *info) +{ + + fts_disableInterrupt(); + + kfree(info->event_dispatch_table); + + free_irq(info->client->irq, info); + +} + +/**@}*/ + +/** +* This function try to attempt to communicate with the IC for the first time during the boot up process in order to acquire the necessary info for the following stages. +* The function execute a system reset, read fundamental info (system info) from the IC and install the interrupt +* @return OK if success or an error code which specify the type of error encountered +*/ +static int fts_init(struct fts_ts_info *info) +{ + int error; + + error = fts_system_reset(); + if (error < OK && isI2cError(error)) { + logError(1, "%s Cannot reset the device! ERROR %08X\n", tag, + error); + return error; + } else { + if (error == (ERROR_TIMEOUT | ERROR_SYSTEM_RESET_FAIL)) { + logError(1, "%s Setting default Sys INFO! \n", tag); + error = defaultSysInfo(0); + } else { + error = readSysInfo(0); + if (error < OK) { + if (!isI2cError(error)) + error = OK; + logError(1, + "%s Cannot read Sys Info! ERROR %08X\n", + tag, error); + } + } + } + + return error; +} + +/** +* Execute a power cycle in the IC, toggling the power lines (AVDD and DVDD) +* @param info pointer to fts_ts_info struct which contain information of the regulators +* @return 0 if success or another value if fail +*/ +int fts_chip_powercycle(struct fts_ts_info *info) +{ + int error = 0; + + logError(1, "%s %s: Power Cycle Starting... \n", tag, __func__); + logError(1, "%s %s: Disabling IRQ... \n", tag, __func__); + + fts_disableInterruptNoSync(); + + if (info->vdd_reg) { + error = regulator_disable(info->vdd_reg); + if (error < 0) { + logError(1, "%s %s: Failed to disable DVDD regulator\n", + tag, __func__); + } + } + + if (info->avdd_reg) { + error = regulator_disable(info->avdd_reg); + if (error < 0) { + logError(1, "%s %s: Failed to disable AVDD regulator\n", + tag, __func__); + } + } + + if (info->board->reset_gpio != GPIO_NOT_DEFINED) + gpio_set_value(info->board->reset_gpio, 0); + else + mdelay(300); + + if (info->vdd_reg) { + error = regulator_enable(info->vdd_reg); + if (error < 0) { + logError(1, "%s %s: Failed to enable DVDD regulator\n", + tag, __func__); + } + } + + mdelay(1); + + if (info->avdd_reg) { + error = regulator_enable(info->avdd_reg); + if (error < 0) { + logError(1, "%s %s: Failed to enable AVDD regulator\n", + tag, __func__); + } + } + + mdelay(5); + + if (info->board->reset_gpio != GPIO_NOT_DEFINED) { + mdelay(10); + gpio_set_value(info->board->reset_gpio, 1); + } + + release_all_touches(info); + + logError(1, "%s %s: Power Cycle Finished! ERROR CODE = %08x\n", tag, + __func__, error); + setSystemResetedUp(1); + setSystemResetedDown(1); + return error; +} + +/** + * Complete the boot up process, initializing the sensing of the IC according to the current setting chosen by the host and register the notifier for the suspend/resume actions and the event handler + * @return OK if success or an error code which specify the type of error encountered + */ +static int fts_init_sensing(struct fts_ts_info *info) +{ + int error = 0; +#ifdef CONFIG_DRM + error |= msm_drm_register_client(&info->notifier); +#endif + error |= fts_interrupt_install(info); + error |= fts_mode_handler(info, 0); +#ifdef CONFIG_FTS_FOD_AREA_REPORT + error |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + error |= setScanMode(SCAN_MODE_ACTIVE, 0x01); +#endif + error |= fts_enableInterrupt(); + + if (error < OK) + logError(1, "%s %s Init after Probe error (ERROR = %08X)\n", + tag, __func__, error); + + return error; +} + +/** + * @ingroup mode_section + * @{ + */ +/** + * The function handle the switching of the mode in the IC enabling/disabling the sensing and the features set from the host + * @param info pointer to fts_ts_info which contains info about the device and its hw setup + * @param force if 1, the enabling/disabling command will be send even if the feature was alredy enabled/disabled otherwise it will judge if the feature changed status or the IC had s system reset and therefore the features need to be restored + * @return OK if success or an error code which specify the type of error encountered + */ +static int fts_mode_handler(struct fts_ts_info *info, int force) +{ + int res = OK; + int ret = OK; + u8 settings[4] = { 0 }; +#ifdef CONFIG_FTS_FOD_AREA_REPORT + u8 gesture_cmd[6] = {0xA2, 0x03, 0x20, 0x00, 0x00, 0x01}; + u8 single_only_cmd[4] = {0xC0, 0x02, 0x00, 0x00}; + u8 single_double_cmd[4] = {0xC0, 0x02, 0x01, 0x1E}; +#endif +#ifdef CONFIG_FTS_FOD_AREA_REPORT + mutex_lock(&info->fod_mutex); +#endif + info->mode = MODE_NOTHING; + logError(0, "%s %s: Mode Handler starting... \n", tag, __func__); + switch (info->resume_bit) { + case 0: + logError(0, "%s %s: Screen OFF... \n", tag, __func__); + +#ifdef CONFIG_FTS_FOD_AREA_REPORT + if (info->fod_status) { + logError(1, "%s %s: Sense OFF by FOD \n", tag, __func__); + logError(1, "%s %s,send long press and gesture cmd\n", tag, __func__); + res = fts_write_dma_safe(gesture_cmd, ARRAY_SIZE(gesture_cmd)); + if (res < OK) + logError(1, "%s %s: enter gesture and longpress failed! ERROR %08X recovery in senseOff...\n", + tag, __func__, res); + res = setScanMode(SCAN_MODE_LOW_POWER, 0); + res |= ret; + if (info->gesture_enabled == 1) { + res = fts_write_dma_safe(single_double_cmd, ARRAY_SIZE(single_double_cmd)); + if (res < OK) + logError(1, "%s %s: set single and double tap delay time failed! ERROR %08X\n", tag, __func__, res); + } else { + res = fts_write_dma_safe(single_only_cmd, ARRAY_SIZE(single_only_cmd)); + if (res < OK) + logError(1, "%s %s: set single only delay time failed! ERROR %08X\n", tag, __func__, res); + } + info->fod_status_set = true; + } else { +#endif + logError(1, "%s %s: Sense OFF! \n", tag, __func__); + ret = setScanMode(SCAN_MODE_ACTIVE, 0x00); + res |= ret; + + if (info->gesture_enabled == 1) { + logError(1, "%s %s: enter in gesture mode ! \n", tag, + __func__); + res = enterGestureMode(isSystemResettedDown()); + if (res >= OK) { + fromIDtoMask(FEAT_SEL_GESTURE, + (u8 *)&info->mode, + sizeof(info->mode)); + MODE_LOW_POWER(info->mode, 0); + } else { + logError(1, + "%s %s: enterGestureMode failed! ERROR %08X recovery in senseOff...\n", + tag, __func__, res); + } + } + info->fod_status_set = false; +#ifdef CONFIG_FTS_FOD_AREA_REPORT + } +#endif + setSystemResetedDown(0); + break; + + case 1: + logError(1, "%s %s: Screen ON... \n", tag, __func__); + +#ifdef GLOVE_MODE + if ((info->glove_enabled == FEAT_ENABLE && isSystemResettedUp()) + || force == 1) { + logError(0, "%s %s: Glove Mode setting... \n", tag, + __func__); + settings[0] = info->glove_enabled; + ret = setFeatures(FEAT_SEL_GLOVE, settings, 1); + if (ret < OK) { + logError(1, + "%s %s: error during setting GLOVE_MODE! ERROR %08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->glove_enabled == FEAT_ENABLE) { + fromIDtoMask(FEAT_SEL_GLOVE, + (u8 *)&info->mode, + sizeof(info->mode)); + logError(1, "%s %s: GLOVE_MODE Enabled! \n", + tag, __func__); + } else { + logError(1, "%s %s: GLOVE_MODE Disabled! \n", + tag, __func__); + } + + } +#endif + +#ifdef COVER_MODE + if ((info->cover_enabled == FEAT_ENABLE && isSystemResettedUp()) + || force == 1) { + logError(0, "%s %s: Cover Mode setting... \n", tag, + __func__); + settings[0] = info->cover_enabled; + ret = setFeatures(FEAT_SEL_COVER, settings, 1); + if (ret < OK) { + logError(1, + "%s %s: error during setting COVER_MODE! ERROR %08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->cover_enabled == FEAT_ENABLE) { + fromIDtoMask(FEAT_SEL_COVER, + (u8 *)&info->mode, + sizeof(info->mode)); + logError(1, "%s %s: COVER_MODE Enabled! \n", + tag, __func__); + } else { + logError(1, "%s %s: COVER_MODE Disabled! \n", + tag, __func__); + } + + } +#endif +#ifdef CHARGER_MODE + if ((info->charger_enabled > 0 && isSystemResettedUp()) + || force == 1) { + logError(0, "%s %s: Charger Mode setting... \n", tag, + __func__); + + settings[0] = info->charger_enabled; + ret = setFeatures(FEAT_SEL_CHARGER, settings, 1); + if (ret < OK) { + logError(1, + "%s %s: error during setting CHARGER_MODE! ERROR %08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->charger_enabled == FEAT_ENABLE) { + fromIDtoMask(FEAT_SEL_CHARGER, + (u8 *)&info->mode, + sizeof(info->mode)); + logError(1, "%s %s: CHARGER_MODE Enabled! \n", + tag, __func__); + } else { + logError(1, "%s %s: CHARGER_MODE Disabled! \n", + tag, __func__); + } + + } +#endif + +#ifdef GRIP_MODE + if ((info->grip_enabled == FEAT_ENABLE && isSystemResettedUp()) + || force == 1) { + logError(0, "%s %s: Grip Mode setting... \n", tag, + __func__); + settings[0] = info->grip_enabled; + ret = setFeatures(FEAT_SEL_GRIP, settings, 1); + if (ret < OK) { + logError(1, + "%s %s: error during setting GRIP_MODE! ERROR %08X\n", + tag, __func__, ret); + } + res |= ret; + + if (ret >= OK && info->grip_enabled == FEAT_ENABLE) { + fromIDtoMask(FEAT_SEL_GRIP, (u8 *)&info->mode, + sizeof(info->mode)); + logError(1, "%s %s: GRIP_MODE Enabled! \n", tag, + __func__); + } else { + logError(1, "%s %s: GRIP_MODE Disabled! \n", + tag, __func__); + } + + } +#endif +#ifdef CONFIG_FTS_FOD_AREA_REPORT + if (info->fod_id) { + logError(1, "%s %s: Sense OFF \n", tag, __func__); + res |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + logError(1, "%s %s: Sense ON without cal \n", tag, __func__); + res |= setScanMode(SCAN_MODE_ACTIVE, 0x20); + } else { + logError(1, "%s %s: Sense ON\n", tag, __func__); + res |= setScanMode(SCAN_MODE_ACTIVE, 0x01); + } + info->sensor_scan = true; + if (info->fod_status) { + res = fts_write_dma_safe(gesture_cmd, ARRAY_SIZE(gesture_cmd)); + if (res < OK) + logError(1, "%s %s: enter gesture and longpress failed! ERROR %08X recovery in senseOff...\n", + tag, __func__, res); + info->fod_status_set = true; + } +#else + settings[0] = 0x01; + logError(1, "%s %s: Sense ON! \n", tag, __func__); + res |= setScanMode(SCAN_MODE_ACTIVE, settings[0]); + info->mode |= (SCAN_MODE_ACTIVE << 24); + MODE_ACTIVE(info->mode, settings[0]); +#endif + setSystemResetedUp(0); + break; + + default: + logError(1, + "%s %s: invalid resume_bit value = %d! ERROR %08X \n", + tag, __func__, info->resume_bit, ERROR_OP_NOT_ALLOW); + res = ERROR_OP_NOT_ALLOW; + } + + logError(0, "%s %s: Mode Handler finished! res = %08X mode = %08X \n", + tag, __func__, res, info->mode); +#ifdef CONFIG_FTS_FOD_AREA_REPORT + mutex_unlock(&info->fod_mutex); +#endif + return res; + +} + +static void fts_mode_handler_work(struct work_struct *work) +{ + struct fts_ts_info *info; + + info = container_of(work, struct fts_ts_info, mode_handler_work); + + fts_mode_handler(info, 0); +} + +/** + * Resume work function which perform a system reset, clean all the touches from the linux input system and prepare the ground for enabling the sensing + */ +static void fts_resume_work(struct work_struct *work) +{ + struct fts_ts_info *info; + + info = container_of(work, struct fts_ts_info, resume_work); + fts_disableInterrupt(); +#ifdef CONFIG_SECURE_TOUCH + fts_secure_stop(info, true); +#endif + info->resume_bit = 1; +#ifdef CONFIG_FTS_FOD_AREA_REPORT + if (!info->fod_id) { +#endif + fts_system_reset(); + release_all_touches(info); +#ifdef CONFIG_FTS_FOD_AREA_REPORT + } +#endif + info->fod_status_set = false; + fts_mode_handler(info, 0); + info->sensor_sleep = false; + + fts_enableInterrupt(); +} + +/** + * Suspend work function which clean all the touches from Linux input system and prepare the ground to disabling the sensing or enter in gesture mode + */ +static void fts_suspend_work(struct work_struct *work) +{ + struct fts_ts_info *info; + + info = container_of(work, struct fts_ts_info, suspend_work); +#ifdef CONFIG_SECURE_TOUCH + fts_secure_stop(info, true); +#endif + fts_disableInterrupt(); + info->resume_bit = 0; + fts_mode_handler(info, 0); + release_all_touches(info); + + info->sensor_sleep = true; + + if (info->gesture_enabled || info->fod_status) + fts_enableInterrupt(); +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + sysfs_notify(&fts_info->fts_touch_dev->kobj, NULL, + "touch_suspend_notify"); +#endif +} + +#ifdef CONFIG_DRM +/**@}*/ + +/** + * Callback function used to detect the suspend/resume events generated by clicking the power button. + * This function schedule a suspend or resume work according to the event received. + */ +static int fts_drm_state_chg_callback(struct notifier_block *nb, + unsigned long val, void *data) +{ + struct fts_ts_info *info = + container_of(nb, struct fts_ts_info, notifier); + struct msm_drm_notifier *evdata = data; + unsigned int blank; + + logError(0, "%s %s: fts notifier begin!\n", tag, __func__); + + if (evdata && evdata->data && info) { + + blank = *(int *)(evdata->data); + logError(1, "%s %s: val:%lu,blank:%u\n", tag, __func__, val, blank); + + if (val == MSM_DRM_EARLY_EVENT_BLANK && (blank == MSM_DRM_BLANK_POWERDOWN || + blank == MSM_DRM_BLANK_LP1 || blank == MSM_DRM_BLANK_LP2)) { + if (info->sensor_sleep) + return NOTIFY_OK; + + logError(1, "%s %s: FB_BLANK %s\n", tag, + __func__, blank == MSM_DRM_BLANK_POWERDOWN ? "POWER DOWN" : "LP"); + + flush_workqueue(info->event_wq); + queue_work(info->event_wq, &info->suspend_work); + } else if (val == MSM_DRM_EVENT_BLANK && blank == MSM_DRM_BLANK_UNBLANK) { + if (!info->sensor_sleep) + return NOTIFY_OK; + + logError(1, "%s %s: FB_BLANK_UNBLANK\n", tag, + __func__); + + flush_workqueue(info->event_wq); + queue_work(info->event_wq, &info->resume_work); + } + } + return NOTIFY_OK; +} + +static struct notifier_block fts_noti_block = { + .notifier_call = fts_drm_state_chg_callback, +}; +#endif + +/** + * From the name of the power regulator get/put the actual regulator structs (copying their references into fts_ts_info variable) + * @param info pointer to fts_ts_info which contains info about the device and its hw setup + * @param get if 1, the regulators are get otherwise they are put (released) back to the system + * @return OK if success or an error code which specify the type of error encountered + */ +static int fts_get_reg(struct fts_ts_info *info, bool get) +{ + int retval; + const struct fts_hw_platform_data *bdata = info->board; + + if (!get) { + retval = 0; + goto regulator_put; + } + + if ((bdata->vdd_reg_name != NULL) && (*bdata->vdd_reg_name != 0)) { + info->vdd_reg = regulator_get(info->dev, bdata->vdd_reg_name); + if (IS_ERR(info->vdd_reg)) { + logError(1, "%s %s: Failed to get power regulator\n", + tag, __func__); + retval = PTR_ERR(info->vdd_reg); + goto regulator_put; + } + } + + if ((bdata->avdd_reg_name != NULL) && (*bdata->avdd_reg_name != 0)) { + info->avdd_reg = regulator_get(info->dev, bdata->avdd_reg_name); + if (IS_ERR(info->avdd_reg)) { + logError(1, + "%s %s: Failed to get bus pullup regulator\n", + tag, __func__); + retval = PTR_ERR(info->avdd_reg); + goto regulator_put; + } + } + + return OK; + +regulator_put: + if (info->vdd_reg) { + regulator_put(info->vdd_reg); + info->vdd_reg = NULL; + } + + if (info->avdd_reg) { + regulator_put(info->avdd_reg); + info->avdd_reg = NULL; + } + + return retval; +} + +/** + * Enable or disable the power regulators + * @param info pointer to fts_ts_info which contains info about the device and its hw setup + * @param enable if 1, the power regulators are turned on otherwise they are turned off + * @return OK if success or an error code which specify the type of error encountered + */ +static int fts_enable_reg(struct fts_ts_info *info, bool enable) +{ + int retval; + + if (!enable) { + retval = 0; + goto disable_pwr_reg; + } + + if (info->vdd_reg) { + retval = regulator_enable(info->vdd_reg); + if (retval < 0) { + logError(1, "%s %s: Failed to enable bus regulator\n", + tag, __func__); + goto exit; + } + } + + if (info->avdd_reg) { + retval = regulator_enable(info->avdd_reg); + if (retval < 0) { + logError(1, "%s %s: Failed to enable power regulator\n", + tag, __func__); + goto disable_bus_reg; + } + } + + return OK; + +disable_pwr_reg: + if (info->avdd_reg) + regulator_disable(info->vdd_reg); + +disable_bus_reg: + if (info->vdd_reg) + regulator_disable(info->avdd_reg); + +exit: + return retval; +} + +/** + * Configure a GPIO according to the parameters + * @param gpio gpio number + * @param config if true, the gpio is set up otherwise it is free + * @param dir direction of the gpio, 0 = in, 1 = out + * @param state initial value (if the direction is in, this parameter is ignored) + * return error code + */ +static int fts_gpio_setup(int gpio, bool config, int dir, int state) +{ + int retval = 0; + unsigned char buf[16]; + + if (config) { + snprintf(buf, 16, "fts_gpio_%u\n", gpio); + + retval = gpio_request(gpio, buf); + if (retval) { + logError(1, "%s %s: Failed to get gpio %d (code: %d)", + tag, __func__, gpio, retval); + return retval; + } + + if (dir == 0) + retval = gpio_direction_input(gpio); + else + retval = gpio_direction_output(gpio, state); + if (retval) { + logError(1, "%s %s: Failed to set gpio %d direction", + tag, __func__, gpio); + return retval; + } + } else { + gpio_free(gpio); + } + + return retval; +} + +/** + * Setup the IRQ and RESET (if present) gpios. + * If the Reset Gpio is present it will perform a cycle HIGH-LOW-HIGH in order to assure that the IC has been reset properly + */ +static int fts_set_gpio(struct fts_ts_info *info) +{ + int retval; + struct fts_hw_platform_data *bdata = info->board; + + retval = fts_gpio_setup(bdata->irq_gpio, true, 0, 0); + if (retval < 0) { + logError(1, "%s %s: Failed to configure irq GPIO\n", tag, + __func__); + goto err_gpio_irq; + } + + if (bdata->reset_gpio >= 0) { + retval = fts_gpio_setup(bdata->reset_gpio, true, 1, 0); + if (retval < 0) { + logError(1, "%s %s: Failed to configure reset GPIO\n", + tag, __func__); + goto err_gpio_reset; + } + } + if (bdata->reset_gpio >= 0) { + gpio_set_value(bdata->reset_gpio, 0); + mdelay(10); + gpio_set_value(bdata->reset_gpio, 1); + } + + return OK; + +err_gpio_reset: + fts_gpio_setup(bdata->irq_gpio, false, 0, 0); + bdata->reset_gpio = GPIO_NOT_DEFINED; +err_gpio_irq: + return retval; +} + +static int fts_pinctrl_init(struct fts_ts_info *info) +{ + int retval = 0; + /* Get pinctrl if target uses pinctrl */ + info->ts_pinctrl = devm_pinctrl_get(info->dev); + + if (IS_ERR_OR_NULL(info->ts_pinctrl)) { + retval = PTR_ERR(info->ts_pinctrl); + dev_err(info->dev, "Target does not use pinctrl %d\n", retval); + goto err_pinctrl_get; + } + + info->pinctrl_state_active + = pinctrl_lookup_state(info->ts_pinctrl, PINCTRL_STATE_ACTIVE); + + if (IS_ERR_OR_NULL(info->pinctrl_state_active)) { + retval = PTR_ERR(info->pinctrl_state_active); + dev_err(info->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_ACTIVE, retval); + goto err_pinctrl_lookup; + } + + info->pinctrl_state_suspend + = pinctrl_lookup_state(info->ts_pinctrl, PINCTRL_STATE_SUSPEND); + + if (IS_ERR_OR_NULL(info->pinctrl_state_suspend)) { + retval = PTR_ERR(info->pinctrl_state_suspend); + dev_dbg(info->dev, "Can not lookup %s pinstate %d\n", + PINCTRL_STATE_SUSPEND, retval); + goto err_pinctrl_lookup; + } + + return 0; +err_pinctrl_lookup: + devm_pinctrl_put(info->ts_pinctrl); +err_pinctrl_get: + info->ts_pinctrl = NULL; + return retval; +} + +/** + * Retrieve and parse the hw information from the device tree node defined in the system. + * the most important information to obtain are: IRQ and RESET gpio numbers, power regulator names + * In the device file node is possible to define additional optional information that can be parsed here. + */ +static int parse_dt(struct device *dev, struct fts_hw_platform_data *bdata) +{ + int retval; + const char *name; + struct device_node *temp, *np = dev->of_node; + struct fts_config_info *config_info; + u32 temp_val; + + bdata->irq_gpio = of_get_named_gpio_flags(np, "fts,irq-gpio", 0, NULL); + + logError(0, "%s irq_gpio = %d\n", tag, bdata->irq_gpio); + + retval = of_property_read_string(np, "fts,pwr-reg-name", &name); + if (retval == -EINVAL) + bdata->vdd_reg_name = NULL; + else if (retval < 0) + return retval; + else { + bdata->vdd_reg_name = name; + logError(0, "%s pwr_reg_name = %s\n", tag, name); + } + + retval = of_property_read_string(np, "fts,bus-reg-name", &name); + if (retval == -EINVAL) + bdata->avdd_reg_name = NULL; + else if (retval < 0) + return retval; + else { + bdata->avdd_reg_name = name; + logError(0, "%s bus_reg_name = %s\n", tag, name); + } + + if (of_property_read_bool(np, "fts,reset-gpio-enable")) { + bdata->reset_gpio = of_get_named_gpio_flags(np, + "fts,reset-gpio", 0, + NULL); + logError(0, "%s reset_gpio =%d\n", tag, bdata->reset_gpio); + } else { + bdata->reset_gpio = GPIO_NOT_DEFINED; + } + + retval = of_property_read_u32(np, "fts,irq-flags", &temp_val); + if (retval < 0) + return retval; + else + bdata->irq_flags = temp_val; + retval = of_property_read_u32(np, "fts,x-max", &temp_val); + if (retval < 0) + bdata->x_max = X_AXIS_MAX; + else + bdata->x_max = temp_val; + + retval = of_property_read_u32(np, "fts,y-max", &temp_val); + if (retval < 0) + bdata->y_max = Y_AXIS_MAX; + else + bdata->y_max = temp_val; + retval = of_property_read_string(np, "fts,default-fw-name", + &bdata->default_fw_name); + +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + bdata->dump_click_count = + of_property_read_bool(np, "fts,dump-click-count"); +#endif + retval = + of_property_read_u32(np, "fts,config-array-size", + (u32 *)&bdata->config_array_size); + + if (retval) { + logError(1, "%s Unable to get array size\n", tag); + return retval; + } + + bdata->config_array = devm_kzalloc(dev, bdata->config_array_size * + sizeof(struct fts_config_info), + GFP_KERNEL); + + if (!bdata->config_array) { + logError(1, "%s Unable to allocate memory\n", tag); + return -ENOMEM; + } + + config_info = bdata->config_array; + for_each_child_of_node(np, temp) { + retval = of_property_read_u32(temp, "fts,tp-vendor", &temp_val); + + if (retval) { + logError(1, "%s Unable to read tp vendor\n", tag); + } else { + config_info->tp_vendor = (u8) temp_val; + logError(1, "%s %s:tp vendor: %u", tag, __func__, + config_info->tp_vendor); + } + retval = of_property_read_u32(temp, "fts,tp-color", &temp_val); + if (retval) { + logError(1, "%s Unable to read tp color\n", tag); + } else { + config_info->tp_color = (u8) temp_val; + logError(1, "%s %s:tp color: %u", tag, __func__, + config_info->tp_color); + } + + retval = + of_property_read_u32(temp, "fts,tp-hw-version", &temp_val); + + if (retval) { + logError(1, "%s Unable to read tp hw version\n", tag); + } else { + config_info->tp_hw_version = (u8) temp_val; + logError(1, "%s %s:tp color: %u", tag, __func__, + config_info->tp_hw_version); + } + + retval = of_property_read_string(temp, "fts,fw-name", + &config_info->fts_cfg_name); + + if (retval && (retval != -EINVAL)) { + logError(1, "%s Unable to read cfg name\n", tag); + } else { + logError(1, "%s %s:fw_name: %s", tag, __func__, + config_info->fts_cfg_name); + } + retval = of_property_read_string(temp, "fts,limit-name", + &config_info->fts_limit_name); + + if (retval && (retval != -EINVAL)) { + logError(1, "%s Unable to read limit name\n", tag); + } else { + logError(1, "%s %s:limit_name: %s", tag, __func__, + config_info->fts_limit_name); + } +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + if (bdata->dump_click_count) { + retval = + of_property_read_string(temp, + "fts,clicknum-file-name", + &config_info->clicknum_file_name); + if (retval && (retval != -EINVAL)) { + dev_err(dev, + "Unable to read click count file name\n"); + } else + dev_err(dev, "%s\n", + config_info->clicknum_file_name); + } +#endif + + config_info++; + } + return OK; +} + +static void fts_switch_mode_work(struct work_struct *work) +{ + struct fts_mode_switch *ms = + container_of(work, struct fts_mode_switch, switch_mode_work); + + struct fts_ts_info *info = ms->info; + unsigned char value = ms->mode; + static const char *fts_gesture_on = "01 20"; + char *gesture_result; + int size = 6 * 2 + 1; + char ch[16] = { 0x0, }; + + logError(1, "%s %s mode:%d\n", tag, __func__, value); + + if (value >= INPUT_EVENT_WAKUP_MODE_OFF + && value <= INPUT_EVENT_WAKUP_MODE_ON) { + info->gesture_enabled = value - INPUT_EVENT_WAKUP_MODE_OFF; + if (info->gesture_enabled) { + gesture_result = (u8 *) kzalloc(size, GFP_KERNEL); + if (gesture_result != NULL) { + fts_gesture_mask_store(info->dev, NULL, + fts_gesture_on, + strlen(fts_gesture_on)); + fts_gesture_mask_show(info->dev, NULL, + gesture_result); + if (strncmp + ("{ 00000000 }", gesture_result, size - 1)) + logError(1, + "%s %s:store gesture mask error\n", + tag, __func__); + kfree(gesture_result); + gesture_result = NULL; + } + } + snprintf(ch, sizeof(ch), "%s", + (value - + INPUT_EVENT_WAKUP_MODE_OFF) ? "enabled" : "disabled"); + } else if (value >= INPUT_EVENT_COVER_MODE_OFF + && value <= INPUT_EVENT_COVER_MODE_ON) { + info->glove_enabled = value - INPUT_EVENT_COVER_MODE_OFF; + fts_mode_handler(info, 1); + } +#ifdef EDGEHOVER_FOR_VOLUME + if (value >= INPUT_EVENT_SLIDE_FOR_VOLUME + && value <= INPUT_EVENT_LONG_SINGLE_TAP_FOR_VOLUME) { + info->volume_type = value; + if (fts_info->volume_type == INPUT_EVENT_SINGLE_TAP_FOR_VOLUME) { + fts_info->single_press_time_low = 30; + fts_info->single_press_time_hi = 800; + } else if (fts_info->volume_type == + INPUT_EVENT_LONG_SINGLE_TAP_FOR_VOLUME) { + fts_info->single_press_time_low = 300; + fts_info->single_press_time_hi = 800; + } + } +#endif +#ifdef PHONE_PALM + if (value >= INPUT_EVENT_PALM_OFF && value <= INPUT_EVENT_PALM_ON) + info->palm_enabled = value - INPUT_EVENT_PALM_OFF; +#endif + if (ms != NULL) { + kfree(ms); + ms = NULL; + } +} + +static int fts_input_event(struct input_dev *dev, unsigned int type, + unsigned int code, int value) +{ + struct fts_ts_info *info = input_get_drvdata(dev); + struct fts_mode_switch *ms; + + logError(1, "%s %s:set input event value = %d\n", tag, __func__, value); + + if (!info) { + printk("%s fts_ts_info is NULL\n", __func__); + return 0; + } + + if (type == EV_SYN && code == SYN_CONFIG) { + if (value >= INPUT_EVENT_START && value <= INPUT_EVENT_END) { + ms = (struct fts_mode_switch *) + kmalloc(sizeof(struct fts_mode_switch), GFP_ATOMIC); + + if (ms != NULL) { + ms->info = info; + ms->mode = (unsigned char)value; + INIT_WORK(&ms->switch_mode_work, + fts_switch_mode_work); + schedule_work(&ms->switch_mode_work); + } else { + logError(1, + "%s %s:failed in allocating memory for switching mode\n", + tag, __func__); + return -ENOMEM; + } + } else { + logError(1, "%s %s:Invalid event value\n", tag, + __func__); + return -EINVAL; + } + } + + return 0; +} + +static int fts_short_open_test(void) +{ + TestToDo selftests; + int res = -1; + int init_type = SPECIAL_PANEL_INIT; + + memset(&selftests, 0x00, sizeof(TestToDo)); + +/* Hover Test */ + selftests.SelfHoverForceRaw = 0; /* SS Hover Force Raw min/Max test */ + selftests.SelfHoverSenceRaw = 0; /* SS Hover Sence Raw min/Max test */ + selftests.SelfHoverForceIxTotal = 0; /* SS Hover Total Force Ix min/Max (for each node)* test */ + selftests.SelfHoverSenceIxTotal = 0; + + selftests.MutualRawAdjITO = 0; + selftests.MutualRaw = 0; + selftests.MutualRawEachNode = 1; + selftests.MutualRawGap = 0; + selftests.MutualRawAdj = 0; + selftests.MutualRawLP = 0; + selftests.MutualRawGapLP = 0; + selftests.MutualRawAdjLP = 0; + selftests.MutualCx1 = 0; + selftests.MutualCx2 = 0; + selftests.MutualCx2Adj = 0; + selftests.MutualCxTotal = 0; + selftests.MutualCxTotalAdj = 0; + selftests.MutualCx1LP = 0; + selftests.MutualCx2LP = 0; + selftests.MutualCx2AdjLP = 0; + selftests.MutualCxTotalLP = 0; + selftests.MutualCxTotalAdjLP = 0; +#ifdef PHONE_KEY + selftests.MutualKeyRaw = 0; +#else + selftests.MutualKeyRaw = 0; +#endif + selftests.MutualKeyCx1 = 0; + selftests.MutualKeyCx2 = 0; +#ifdef PHONE_KEY + selftests.MutualKeyCxTotal = 0; +#else + selftests.MutualKeyCxTotal = 0; +#endif + selftests.SelfForceRaw= 1; + selftests.SelfForceRawGap = 0; + selftests.SelfForceRawLP = 0; + selftests.SelfForceRawGapLP = 0; + selftests.SelfForceIx1 = 0; + selftests.SelfForceIx2 = 0; + selftests.SelfForceIx2Adj = 0; + selftests.SelfForceIxTotal = 0; + selftests.SelfForceIxTotalAdj = 0; + selftests.SelfForceCx1 = 0; + selftests.SelfForceCx2 = 0; + selftests.SelfForceCx2Adj = 0; + selftests.SelfForceCxTotal = 0; + selftests.SelfForceCxTotalAdj = 0; + selftests.SelfSenseRaw = 1; + selftests.SelfSenseRawGap = 0; + selftests.SelfSenseRawLP = 0; + selftests.SelfSenseRawGapLP = 0; + selftests.SelfSenseIx1 = 0; + selftests.SelfSenseIx2 = 0; + selftests.SelfSenseIx2Adj = 0; + selftests.SelfSenseIxTotal = 0; + selftests.SelfSenseIxTotalAdj = 0; + selftests.SelfSenseCx1 = 0; + selftests.SelfSenseCx2 = 0; + selftests.SelfSenseCx2Adj = 0; + selftests.SelfSenseCxTotal = 0; + selftests.SelfSenseCxTotalAdj = 0; + + res = fts_disableInterrupt(); + if (res < 0) { + logError(0, "%s fts_disableInterrupt: ERROR %08X \n", + tag, res); + res = (res | ERROR_DISABLE_INTER); + goto END; + } + res = production_test_main(LIMITS_FILE, 1, init_type, &selftests); +END: + fts_mode_handler(fts_info, 1); + fts_enableInterrupt(); + if (res == OK) + return FTS_RESULT_PASS; + else + return FTS_RESULT_FAIL; +} + +static int fts_i2c_test(void) +{ + int ret = 0; + u8 data[SYS_INFO_SIZE] = { 0 }; + + logError(0, "%s %s: Reading System Info...\n", tag, __func__); + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, ADDR_FRAMEBUFFER, + data, SYS_INFO_SIZE, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, + "%s %s: error while reading the system data ERROR %08X\n", + tag, __func__, ret); + return FTS_RESULT_FAIL; + } + + return FTS_RESULT_PASS; +} + +static ssize_t fts_selftest_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + char tmp[5] = { 0 }; + int cnt; + + if (*pos != 0) + return 0; + cnt = + snprintf(tmp, sizeof(fts_info->result_type), "%d\n", + fts_info->result_type); + if (copy_to_user(buf, tmp, strlen(tmp))) { + return -EFAULT; + } + *pos += cnt; + return cnt; +} + +static ssize_t fts_selftest_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int retval = 0; + char tmp[6]; + + if (copy_from_user(tmp, buf, count)) { + retval = -EFAULT; + goto out; + } + + if (!strncmp("short", tmp, 5) || !strncmp("open", tmp, 4)) { + retval = fts_short_open_test(); + } else if (!strncmp("i2c", tmp, 3)) + retval = fts_i2c_test(); + + fts_info->result_type = retval; +out: + if (retval >= 0) + retval = count; + + return retval; +} + +static const struct file_operations fts_selftest_ops = { + .read = fts_selftest_read, + .write = fts_selftest_write, +}; + +static ssize_t fts_datadump_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int ret = 0, cnt1 = 0, cnt2 = 0, cnt3 = 0; + char *tmp; + + if (*pos != 0) + return 0; + + tmp = vmalloc(PAGE_SIZE * 2); + if (tmp == NULL) + return 0; + else + memset(tmp, 0, PAGE_SIZE * 2); + + cnt1 = fts_strength_frame_show(fts_info->dev, NULL, tmp); + if (cnt1 == 0) { + ret = 0; + goto out; + } + + ret = stm_fts_cmd_store(fts_info->dev, NULL, "13", 2); + if (ret == 0) + goto out; + cnt2 = stm_fts_cmd_show(fts_info->dev, NULL, tmp + cnt1); + if (cnt2 == 0) { + ret = 0; + goto out; + } + + ret = stm_fts_cmd_store(fts_info->dev, NULL, "15", 2); + if (ret == 0) + goto out; + cnt3 = stm_fts_cmd_show(fts_info->dev, NULL, tmp + cnt1 + cnt2); + if (cnt3 == 0) { + ret = 0; + goto out; + } + + if (copy_to_user(buf, tmp, cnt1 + cnt2 + cnt3)) + ret = -EFAULT; + +out: + if (tmp) { + vfree(tmp); + tmp = NULL; + } + *pos += (cnt1 + cnt2 + cnt3); + if (ret <= 0) + return ret; + return cnt1 + cnt2 + cnt3; +} + +static const struct file_operations fts_datadump_ops = { + .read = fts_datadump_read, +}; + +#define TP_INFO_MAX_LENGTH 50 + +static ssize_t fts_fw_version_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int cnt = 0, ret = 0; + char tmp[TP_INFO_MAX_LENGTH]; + + if (*pos != 0) + return 0; + + cnt = + snprintf(tmp, TP_INFO_MAX_LENGTH, "%x.%x\n", systemInfo.u16_fwVer, + systemInfo.u16_cfgVer); + ret = copy_to_user(buf, tmp, cnt); + *pos += cnt; + if (ret != 0) + return 0; + else + return cnt; +} + +static const struct file_operations fts_fw_version_ops = { + .read = fts_fw_version_read, +}; + +static ssize_t fts_lockdown_info_read(struct file *file, char __user *buf, + size_t count, loff_t *pos) +{ + int cnt = 0, ret = 0; + char tmp[TP_INFO_MAX_LENGTH]; + + if (*pos != 0) + return 0; + + ret = fts_get_lockdown_info(fts_info->lockdown_info, fts_info); + if (ret != OK) { + logError(1, "%s %s get lockdown info error\n", tag, __func__); + goto out; + } + + cnt = + snprintf(tmp, TP_INFO_MAX_LENGTH, + "0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", + fts_info->lockdown_info[0], fts_info->lockdown_info[1], + fts_info->lockdown_info[2], fts_info->lockdown_info[3], + fts_info->lockdown_info[4], fts_info->lockdown_info[5], + fts_info->lockdown_info[6], fts_info->lockdown_info[7]); + ret = copy_to_user(buf, tmp, cnt); +out: + *pos += cnt; + if (ret != 0) + return 0; + else + return cnt; +} + +static const struct file_operations fts_lockdown_info_ops = { + .read = fts_lockdown_info_read, +}; + +#ifdef CONFIG_PM +static int fts_pm_suspend(struct device *dev) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + +#ifndef CONFIG_FTS_FOD_AREA_REPORT + if (device_may_wakeup(dev) && info->gesture_enabled) { + logError(1, "%s enable touch irq wake\n", tag); + enable_irq_wake(info->client->irq); + } +#else + enable_irq_wake(info->client->irq); +#endif + info->tp_pm_suspend = true; + reinit_completion(&info->pm_resume_completion); + + return 0; + +} + +static int fts_pm_resume(struct device *dev) +{ + struct fts_ts_info *info = dev_get_drvdata(dev); + +#ifndef CONFIG_FTS_FOD_AREA_REPORT + if (device_may_wakeup(dev) && info->gesture_enabled) { + logError(1, "%s disable touch irq wake\n", tag); + disable_irq_wake(info->client->irq); + } +#else + disable_irq_wake(info->client->irq); +#endif + info->tp_pm_suspend = false; + complete(&info->pm_resume_completion); + + return 0; +} + +static const struct dev_pm_ops fts_dev_pm_ops = { + .suspend = fts_pm_suspend, + .resume = fts_pm_resume, +}; +#endif + +#ifdef CONFIG_TOUCHSCREEN_ST_DEBUG_FS +static void tpdbg_shutdown(struct fts_ts_info *info, bool sleep) +{ + u8 settings[4] = { 0 }; + info->mode = MODE_NOTHING; + + if (sleep) { + logError(0, "%s %s: Sense OFF! \n", tag, __func__); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + } else { + settings[0] = 0x01; + logError(0, "%s %s: Sense ON! \n", tag, __func__); + setScanMode(SCAN_MODE_ACTIVE, settings[0]); + info->mode |= (SCAN_MODE_ACTIVE << 24); + MODE_ACTIVE(info->mode, settings[0]); + } +} + +static void tpdbg_suspend(struct fts_ts_info *info, bool enable) +{ + if (enable) + queue_work(info->event_wq, &info->suspend_work); + else + queue_work(info->event_wq, &info->resume_work); +} + +static int tpdbg_open(struct inode *inode, struct file *file) +{ + file->private_data = inode->i_private; + + return 0; +} + +static ssize_t tpdbg_read(struct file *file, char __user *buf, size_t size, + loff_t *ppos) +{ + const char *str = "cmd support as below:\n \ + \necho \"irq-disable\" or \"irq-enable\" to ctrl irq\n \ + \necho \"tp-sd-en\" of \"tp-sd-off\" to ctrl panel in or off sleep mode\n \ + \necho \"tp-suspend-en\" or \"tp-suspend-off\" to ctrl panel in or off suspend status\n"; + + loff_t pos = *ppos; + int len = strlen(str); + + if (pos < 0) + return -EINVAL; + if (pos >= len) + return 0; + + if (copy_to_user(buf, str, len)) + return -EFAULT; + + *ppos = pos + len; + + return len; +} + +static ssize_t tpdbg_write(struct file *file, const char __user *buf, + size_t size, loff_t *ppos) +{ + struct fts_ts_info *info = file->private_data; + char *cmd = kzalloc(size + 1, GFP_KERNEL); + int ret = size; + + if (!cmd) + return -ENOMEM; + + if (copy_from_user(cmd, buf, size)) { + ret = -EFAULT; + goto out; + } + + cmd[size] = '\0'; + + if (!strncmp(cmd, "irq-disable", 11)) + disable_irq(info->client->irq); + else if (!strncmp(cmd, "irq-enable", 10)) + enable_irq(info->client->irq); + else if (!strncmp(cmd, "tp-sd-en", 8)) + tpdbg_shutdown(info, true); + else if (!strncmp(cmd, "tp-sd-off", 9)) + tpdbg_shutdown(info, false); + else if (!strncmp(cmd, "tp-suspend-en", 13)) + tpdbg_suspend(info, true); + else if (!strncmp(cmd, "tp-suspend-off", 14)) + tpdbg_suspend(info, false); +out: + kfree(cmd); + + return ret; +} + +static int tpdbg_release(struct inode *inode, struct file *file) +{ + file->private_data = NULL; + + return 0; +} + +static const struct file_operations tpdbg_operations = { + .owner = THIS_MODULE, + .open = tpdbg_open, + .read = tpdbg_read, + .write = tpdbg_write, + .release = tpdbg_release, +}; +#endif + +#ifdef CONFIG_SECURE_TOUCH +int fts_secure_init(struct fts_ts_info *info) +{ + int ret; + struct fts_secure_info *scr_info = kmalloc(sizeof(*scr_info), GFP_KERNEL); + if (!scr_info) { + logError(1, "%s %s alloc fts_secure_info failed\n", tag, __func__); + return -ENOMEM; + } + + logError(1, "%s fts_secure_init\n", tag); + + mutex_init(&scr_info->palm_lock); + + init_completion(&scr_info->st_powerdown); + init_completion(&scr_info->st_irq_processed); + + atomic_set(&scr_info->st_enabled, 0); + atomic_set(&scr_info->st_pending_irqs, 0); + + info->secure_info = scr_info; + + ret = sysfs_create_file(&info->dev->kobj, &dev_attr_secure_touch_enable.attr); + if (ret < 0) { + logError(1, "%s %s create sysfs attribute secure_touch_enable failed\n", tag, __func__); + goto err; + } + + ret = sysfs_create_file(&info->dev->kobj, &dev_attr_secure_touch.attr); + if (ret < 0) { + logError(1, "%s %s create sysfs attribute secure_touch failed\n", tag, __func__); + goto err; + } + + scr_info->fts_info = info; + scr_info->secure_inited = true; + + return 0; + +err: + kfree(scr_info); + info->secure_info = NULL; + return ret; +} + +void fts_secure_remove(struct fts_ts_info *info) +{ + struct fts_secure_info *scr_info = info->secure_info; + + sysfs_remove_file(&info->dev->kobj, &dev_attr_secure_touch_enable.attr); + sysfs_remove_file(&info->dev->kobj, &dev_attr_secure_touch.attr); + kfree(scr_info); +} + +#endif + + +/** + * Probe function, called when the driver it is matched with a device with the same name compatible name + * This function allocate, initialize and define all the most important function and flow that are used by the driver to operate with the IC. + * It allocates device variables, initialize queues and schedule works, registers the IRQ handler, suspend/resume callbacks, registers the device to the linux input subsystem etc. + */ +#ifdef I2C_INTERFACE +static int fts_probe(struct i2c_client *client, const struct i2c_device_id *idp) +{ +#else +static int fts_probe(struct spi_device *client) +{ +#endif + + struct fts_ts_info *info = NULL; + int error = 0; + struct device_node *dp = client->dev.of_node; + int retval; + int skip_5_1 = 0; + u16 bus_type; + u8 *tp_maker; + + logError(1, "%s %s: driver ver: %s\n", tag, __func__, + FTS_TS_DRV_VERSION); + +#ifdef I2C_INTERFACE + logError(0, "%s I2C interface... \n", tag); + if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) { + logError(1, "%s Unsupported I2C functionality\n", tag); + error = -EIO; + goto ProbeErrorExit_0; + } + + logError(0, "%s i2c address: %x \n", tag, client->addr); + bus_type = BUS_I2C; +#else + logError(0, "%s SPI interface... \n", tag); + client->mode = SPI_MODE_0; +#ifndef SPI4_WIRE + client->mode |= SPI_3WIRE; +#endif + client->max_speed_hz = SPI_CLOCK_FREQ; + client->bits_per_word = 8; + if (spi_setup(client) < 0) { + logError(1, "%s Unsupported SPI functionality\n", tag); + error = -EIO; + goto ProbeErrorExit_0; + } + bus_type = BUS_SPI; +#endif + + logError(0, "%s SET Device driver INFO: \n", tag); + + info = kzalloc(sizeof(struct fts_ts_info), GFP_KERNEL); + if (!info) { + logError(1, + "%s Out of memory... Impossible to allocate struct info!\n", + tag); + error = -ENOMEM; + goto ProbeErrorExit_0; + } + + fts_info = info; + info->client = client; + info->dev = &info->client->dev; + dev_set_drvdata(info->dev, info); + + if (dp) { + info->board = + devm_kzalloc(&client->dev, + sizeof(struct fts_hw_platform_data), + GFP_KERNEL); + if (!info->board) { + logError(1, "%s ERROR:info.board kzalloc failed \n", + tag); + error = -ENOMEM; + goto ProbeErrorExit_1; + } + parse_dt(&client->dev, info->board); + } + + logError(0, "%s SET Regulators: \n", tag); + retval = fts_get_reg(info, true); + if (retval < 0) { + logError(1, "%s ERROR: %s: Failed to get regulators\n", tag, + __func__); + error = retval; + goto ProbeErrorExit_1; + } + + retval = fts_enable_reg(info, true); + if (retval < 0) { + logError(1, "%s %s: ERROR Failed to enable regulators\n", tag, + __func__); + error = retval; + goto ProbeErrorExit_2; + } + + logError(0, "%s SET GPIOS: \n", tag); + retval = fts_set_gpio(info); + if (retval < 0) { + logError(1, "%s %s: ERROR Failed to set up GPIO's\n", tag, + __func__); + error = retval; + goto ProbeErrorExit_2; + } + + error = fts_pinctrl_init(info); + + if (!error && info->ts_pinctrl) { + error = + pinctrl_select_state(info->ts_pinctrl, + info->pinctrl_state_active); + + if (error < 0) { + dev_err(&client->dev, + "%s: Failed to select %s pinstate %d\n", + __func__, PINCTRL_STATE_ACTIVE, error); + } + } else { + dev_err(&client->dev, "%s: Failed to init pinctrl\n", __func__); + } + + info->client->irq = gpio_to_irq(info->board->irq_gpio); + + logError(0, "%s SET Event Handler: \n", tag); + + info->event_wq = + alloc_workqueue("fts-event-queue", + WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); + if (!info->event_wq) { + logError(1, "%s ERROR: Cannot create work thread\n", tag); + error = -ENOMEM; + goto ProbeErrorExit_4; + } + + info->irq_wq = + alloc_workqueue("fts-irq-queue", + WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); + if (!info->irq_wq) { + logError(1, "%s ERROR: Cannot create irq work thread\n", tag); + error = -ENOMEM; + goto ProbeErrorExit_4; + } + + INIT_WORK(&info->resume_work, fts_resume_work); + INIT_WORK(&info->suspend_work, fts_suspend_work); + INIT_WORK(&info->sleep_work, fts_ts_sleep_work); + INIT_WORK(&info->mode_handler_work, fts_mode_handler_work); + init_completion(&info->tp_reset_completion); + logError(0, "%s SET Input Device Property: \n", tag); + info->dev = &info->client->dev; + info->input_dev = input_allocate_device(); + if (!info->input_dev) { + logError(1, "%s ERROR: No such input device defined! \n", tag); + error = -ENODEV; + goto ProbeErrorExit_5; + } + info->input_dev->dev.parent = &client->dev; + info->input_dev->name = FTS_TS_DRV_NAME; + snprintf(fts_ts_phys, sizeof(fts_ts_phys), "%s/input0", + info->input_dev->name); + info->input_dev->phys = fts_ts_phys; + info->input_dev->id.bustype = bus_type; + info->input_dev->id.vendor = 0x0001; + info->input_dev->id.product = 0x0002; + info->input_dev->id.version = 0x0100; + info->input_dev->event = fts_input_event; + input_set_drvdata(info->input_dev, info); + + __set_bit(EV_SYN, info->input_dev->evbit); + __set_bit(EV_KEY, info->input_dev->evbit); + __set_bit(EV_ABS, info->input_dev->evbit); + __set_bit(BTN_TOUCH, info->input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, info->input_dev->keybit); + /*__set_bit(BTN_TOOL_PEN, info->input_dev->keybit);*/ + + input_mt_init_slots(info->input_dev, TOUCH_ID_MAX, INPUT_MT_DIRECT); + + /*input_mt_init_slots(info->input_dev, TOUCH_ID_MAX); */ + + input_set_abs_params(info->input_dev, ABS_MT_POSITION_X, X_AXIS_MIN, + info->board->x_max - 1, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_POSITION_Y, Y_AXIS_MIN, + info->board->y_max - 1, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_TOUCH_MAJOR, AREA_MIN, + AREA_MAX, 0, 0); + input_set_abs_params(info->input_dev, ABS_MT_WIDTH_MAJOR, AREA_MIN, + AREA_MAX, 0, 0); + +#ifdef CONFIG_FTS_FOD_AREA_REPORT + /*input_set_abs_params(info->input_dev, ABS_MT_PRESSURE, PRESSURE_MIN, PRESSURE_MAX, 0, 0);*/ +#endif + input_set_abs_params(info->input_dev, ABS_MT_DISTANCE, DISTANCE_MIN, + DISTANCE_MAX, 0, 0); + +#ifdef GESTURE_MODE + input_set_capability(info->input_dev, EV_KEY, KEY_WAKEUP); + + input_set_capability(info->input_dev, EV_KEY, KEY_M); + input_set_capability(info->input_dev, EV_KEY, KEY_O); + input_set_capability(info->input_dev, EV_KEY, KEY_E); + input_set_capability(info->input_dev, EV_KEY, KEY_W); + input_set_capability(info->input_dev, EV_KEY, KEY_C); + input_set_capability(info->input_dev, EV_KEY, KEY_L); + input_set_capability(info->input_dev, EV_KEY, KEY_F); + input_set_capability(info->input_dev, EV_KEY, KEY_V); + input_set_capability(info->input_dev, EV_KEY, KEY_S); + input_set_capability(info->input_dev, EV_KEY, KEY_Z); + input_set_capability(info->input_dev, EV_KEY, KEY_WWW); + + input_set_capability(info->input_dev, EV_KEY, KEY_LEFT); + input_set_capability(info->input_dev, EV_KEY, KEY_RIGHT); + input_set_capability(info->input_dev, EV_KEY, KEY_UP); + input_set_capability(info->input_dev, EV_KEY, KEY_DOWN); + + input_set_capability(info->input_dev, EV_KEY, KEY_F1); + input_set_capability(info->input_dev, EV_KEY, KEY_F2); + input_set_capability(info->input_dev, EV_KEY, KEY_F3); + input_set_capability(info->input_dev, EV_KEY, KEY_F4); + input_set_capability(info->input_dev, EV_KEY, KEY_F5); + + input_set_capability(info->input_dev, EV_KEY, KEY_LEFTBRACE); + input_set_capability(info->input_dev, EV_KEY, KEY_RIGHTBRACE); +#endif + +#ifdef PHONE_KEY + /*KEY associated to the touch screen buttons */ + input_set_capability(info->input_dev, EV_KEY, KEY_HOMEPAGE); + input_set_capability(info->input_dev, EV_KEY, KEY_BACK); + input_set_capability(info->input_dev, EV_KEY, KEY_MENU); +#endif +#ifdef CONFIG_FTS_FOD_AREA_REPORT + input_set_capability(info->input_dev, EV_KEY, BTN_INFO); + input_set_capability(info->input_dev, EV_KEY, KEY_INFO); + input_set_capability(info->input_dev, EV_KEY, KEY_GOTO); +#endif + mutex_init(&(info->input_report_mutex)); +#ifdef GESTURE_MODE + mutex_init(&gestureMask_mutex); +#endif + + spin_lock_init(&fts_int); + + /* register the multi-touch input device */ + error = input_register_device(info->input_dev); + if (error) { + logError(1, "%s ERROR: No such input device\n", tag); + error = -ENODEV; + goto ProbeErrorExit_5_1; + } + + skip_5_1 = 1; + /* track slots */ + info->touch_id = 0; +#ifdef STYLUS_MODE + info->stylus_id = 0; +#endif + + /* init feature switches (by default all the features are disable, if one feature want to be enabled from the start, set the corresponding value to 1) */ + info->gesture_enabled = 0; + info->glove_enabled = 0; + info->charger_enabled = 0; + info->cover_enabled = 0; + info->grip_enabled = 0; + info->grip_pixel_def = 30; + info->grip_pixel = info->grip_pixel_def; + + info->resume_bit = 1; + info->lockdown_is_ok = false; +#ifdef CONFIG_DRM + info->notifier = fts_noti_block; +#endif + logError(0, "%s Init Core Lib: \n", tag); + initCore(info); + /* init hardware device */ + logError(0, "%s Device Initialization: \n", tag); + error = fts_init(info); + if (error < OK) { + logError(1, "%s Cannot initialize the device ERROR %08X\n", tag, + error); + error = -ENODEV; + goto ProbeErrorExit_6; + } + /*update_hardware_info(TYPE_TOUCH, 4);*/ + +#ifdef CONFIG_SECURE_TOUCH + logError(1, "%s %s create secure touch file...\n", tag, __func__); + error = fts_secure_init(info); + if (error < 0) { + logError(1, "%s %s init secure touch failed\n", tag, __func__); + goto ProbeErrorExit_7; + } + logError(1, "%s %s create secure touch file successful\n", tag, __func__); + fts_secure_stop(info, 1); +#endif + +#ifdef CONFIG_I2C_BY_DMA + /*dma buf init*/ + info->dma_buf = (struct fts_dma_buf *)kzalloc(sizeof(*info->dma_buf), GFP_KERNEL); + if (!info->dma_buf) { + logError(1, "%s %s:ERROR alloc mem failed!", tag, __func__); + goto ProbeErrorExit_7; + } + mutex_init(&info->dma_buf->dmaBufLock); + info->dma_buf->rdBuf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!info->dma_buf->rdBuf) { + logError(1, "%s %s:ERROR alloc mem failed!", tag, __func__); + goto ProbeErrorExit_7; + } + info->dma_buf->wrBuf = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (!info->dma_buf->wrBuf) { + logError(1, "%s %s:ERROR alloc mem failed!", tag, __func__); + goto ProbeErrorExit_7; + } +#endif + + error = fts_get_lockdown_info(info->lockdown_info, info); + + if (error < OK) + logError(1, "%s can't get lockdown info", tag); + else { + logError(1, + "%s Lockdown:0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x\n", + tag, info->lockdown_info[0], info->lockdown_info[1], + info->lockdown_info[2], info->lockdown_info[3], + info->lockdown_info[4], info->lockdown_info[5], + info->lockdown_info[6], info->lockdown_info[7]); + info->lockdown_is_ok = true; + /*update_hardware_info(TYPE_TP_MAKER, info->lockdown_info[0] - 0x30); */ + } + +#ifdef FW_UPDATE_ON_PROBE + logError(1, "%s FW Update and Sensing Initialization: \n", tag); + error = fts_fw_update(info, NULL, 0); + if (error < OK) { + logError(1, + "%s Cannot execute fw upgrade the device ERROR %08X\n", + tag, error); + error = -ENODEV; + goto ProbeErrorExit_7; + } +#else + logError(0, "%s SET Auto Fw Update: \n", tag); + info->fwu_workqueue = + alloc_workqueue("fts-fwu-queue", + WQ_UNBOUND | WQ_HIGHPRI | WQ_CPU_INTENSIVE, 1); + if (!info->fwu_workqueue) { + logError(1, "%s ERROR: Cannot create fwu work thread\n", tag); + goto ProbeErrorExit_7; + } + INIT_DELAYED_WORK(&info->fwu_work, fts_fw_update_auto); +#endif + info->sensor_scan = true; + + logError(0, "%s SET Device File Nodes: \n", tag); + /* sysfs stuff */ + info->attrs.attrs = fts_attr_group; + error = sysfs_create_group(&client->dev.kobj, &info->attrs); + if (error) { + logError(1, "%s ERROR: Cannot create sysfs structure!\n", tag); + error = -ENODEV; + goto ProbeErrorExit_7; + } + + error = fts_proc_init(); + if (error < OK) + logError(1, "%s Error: can not create /proc file! \n", tag); + + tp_maker = kzalloc(20, GFP_KERNEL); + if (tp_maker == NULL) + logError(1, "%s fail to alloc vendor name memory\n", tag); + else { + kfree(tp_maker); + tp_maker = NULL; + } + device_init_wakeup(&client->dev, 1); + + init_completion(&info->pm_resume_completion); +#ifdef CONFIG_TOUCHSCREEN_ST_DEBUG_FS + info->debugfs = debugfs_create_dir("tp_debug", NULL); + if (info->debugfs) { + debugfs_create_file("switch_state", 0660, info->debugfs, info, + &tpdbg_operations); + } +#endif + + if (info->fts_tp_class == NULL) + info->fts_tp_class = class_create(THIS_MODULE, "touch"); + info->fts_touch_dev = + device_create(info->fts_tp_class, NULL, 0x49, info, "tp_dev"); + + if (IS_ERR(info->fts_touch_dev)) { + logError(1, + "%s ERROR: Failed to create device for the sysfs!\n", + tag); + goto ProbeErrorExit_8; + } + + dev_set_drvdata(info->fts_touch_dev, info); +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + error = + sysfs_create_file(&info->fts_touch_dev->kobj, + &dev_attr_touch_suspend_notify.attr); + + if (error) { + logError(1, "%s ERROR: Failed to create sysfs group!\n", tag); + goto ProbeErrorExit_8; + } +#endif +#ifdef CONFIG_FTS_FOD_AREA_REPORT + mutex_init(&(info->fod_mutex)); + + error = + sysfs_create_file(&info->fts_touch_dev->kobj, + &dev_attr_fod_status.attr); + if (error) { + logError(1, "%s ERROR: Failed to create fod_status sysfs group!\n", tag); + } + error = + sysfs_create_file(&info->fts_touch_dev->kobj, + &dev_attr_fod_test.attr); + if (error) { + logError(1, "%s ERROR: Failed to create fod_test sysfs group!\n", tag); + } +#endif + info->tp_lockdown_info_proc = + proc_create("tp_lockdown_info", 0444, NULL, &fts_lockdown_info_ops); + info->tp_selftest_proc = + proc_create("tp_selftest", 0644, NULL, &fts_selftest_ops); + info->tp_data_dump_proc = + proc_create("tp_data_dump", 0444, NULL, &fts_datadump_ops); + info->tp_fw_version_proc = + proc_create("tp_fw_version", 0444, NULL, &fts_fw_version_ops); + +#ifndef FW_UPDATE_ON_PROBE + queue_delayed_work(info->fwu_workqueue, &info->fwu_work, + msecs_to_jiffies(EXP_FN_WORK_DELAY_MS)); +#endif + + logError(1, "%s Probe Finished! \n", tag); + return OK; +ProbeErrorExit_8: + device_destroy(info->fts_tp_class, 0x49); + class_destroy(info->fts_tp_class); + info->fts_tp_class = NULL; +ProbeErrorExit_7: +#ifdef CONFIG_SECURE_TOUCH + fts_secure_remove(info); +#endif +#ifdef CONFIG_I2C_BY_DMA + if (info->dma_buf) + kfree(info->dma_buf); + if (info->dma_buf->rdBuf) + kfree(info->dma_buf->rdBuf); + if (info->dma_buf->wrBuf) + kfree(info->dma_buf->wrBuf); +#endif +#ifdef CONFIG_DRM + msm_drm_unregister_client(&info->notifier); +#endif + +ProbeErrorExit_6: + input_unregister_device(info->input_dev); + +ProbeErrorExit_5_1: + if (skip_5_1 != 1) + input_free_device(info->input_dev); + +ProbeErrorExit_5: + destroy_workqueue(info->event_wq); + +ProbeErrorExit_4: + fts_enable_reg(info, false); + +ProbeErrorExit_2: + fts_get_reg(info, false); + +ProbeErrorExit_1: + kfree(info); + +ProbeErrorExit_0: + logError(1, "%s Probe Failed!\n", tag); + + return error; +} + +/** + * Clear and free all the resources associated to the driver. + * This function is called when the driver need to be removed. + */ +#ifdef I2C_INTERFACE +static int fts_remove(struct i2c_client *client) +{ +#else +static int fts_remove(struct spi_device *client) +{ +#endif + + struct fts_ts_info *info = dev_get_drvdata(&(client->dev)); + + fts_proc_remove(); + /* sysfs stuff */ + sysfs_remove_group(&client->dev.kobj, &info->attrs); + /* remove interrupt and event handlers */ + fts_interrupt_uninstall(info); +#ifdef CONFIG_DRM + msm_drm_unregister_client(&info->notifier); +#endif + + /* unregister the device */ + input_unregister_device(info->input_dev); + + /* Remove the work thread */ + destroy_workqueue(info->event_wq); +#ifndef FW_UPDATE_ON_PROBE + destroy_workqueue(info->fwu_workqueue); +#endif +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + if (info->board->dump_click_count && !info->current_clicknum_file) { + kfree(info->current_clicknum_file); + info->current_clicknum_file = NULL; + } + sysfs_remove_file(&info->fts_touch_dev->kobj, + &dev_attr_touch_suspend_notify.attr); +#endif + + device_destroy(info->fts_tp_class, DCHIP_ID_0); + class_destroy(info->fts_tp_class); + info->fts_tp_class = NULL; + + fts_enable_reg(info, false); + fts_get_reg(info, false); + fts_info = NULL; +#ifdef CONFIG_SECURE_TOUCH + fts_secure_remove(info); +#endif + /* free all */ + kfree(info); + + return OK; +} + +/** +* Struct which contains the compatible names that need to match with the definition of the device in the device tree node +*/ +static struct of_device_id fts_of_match_table[] = { + { + .compatible = "st,fts", + }, + {}, +}; + +#ifdef I2C_INTERFACE +static const struct i2c_device_id fts_device_id[] = { + {FTS_TS_DRV_NAME, 0}, + {} +}; + +static struct i2c_driver fts_i2c_driver = { + .driver = { + .name = FTS_TS_DRV_NAME, + .of_match_table = fts_of_match_table, +#ifdef CONFIG_PM + .pm = &fts_dev_pm_ops, +#endif + }, + .probe = fts_probe, + .remove = fts_remove, + .id_table = fts_device_id, +}; +#else +static struct spi_driver fts_spi_driver = { + .driver = { + .name = FTS_TS_DRV_NAME, + .of_match_table = fts_of_match_table, + .owner = THIS_MODULE, + }, + .probe = fts_probe, + .remove = fts_remove, +}; +#endif + +static int __init fts_driver_init(void) +{ +#ifdef I2C_INTERFACE + return i2c_add_driver(&fts_i2c_driver); +#else + return spi_register_driver(&fts_spi_driver); +#endif +} + +static void __exit fts_driver_exit(void) +{ +#ifdef I2C_INTERFACE + i2c_del_driver(&fts_i2c_driver); +#else + spi_unregister_driver(&fts_spi_driver); +#endif + +} + +MODULE_DESCRIPTION("STMicroelectronics MultiTouch IC Driver"); +MODULE_AUTHOR("STMicroelectronics"); +MODULE_LICENSE("GPL"); + +late_initcall(fts_driver_init); +module_exit(fts_driver_exit); diff --git a/drivers/input/touchscreen/fts_521/fts.h b/drivers/input/touchscreen/fts_521/fts.h new file mode 100644 index 000000000000..ac436b341329 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts.h @@ -0,0 +1,385 @@ +/* + * fts.c + * + * FTS Capacitive touch screen controller (FingerTipS) + * + * Copyright (C) 2017, STMicroelectronics + * Authors: AMG(Analog Mems Group) + * + * marco.cali@st.com + * + * 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. + * + * THE PRESENT SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES + * OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, FOR THE SOLE + * PURPOSE TO SUPPORT YOUR APPLICATION DEVELOPMENT. + * AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, + * INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE + * CONTENT OF SUCH SOFTWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING + * INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. + * + * THIS SOFTWARE IS SPECIFICALLY DESIGNED FOR EXCLUSIVE USE WITH ST PARTS. + */ + +/*! +* \file fts.h +* \brief Contains all the definitions and structs used generally by the driver +*/ + +#ifndef _LINUX_FTS_I2C_H_ +#define _LINUX_FTS_I2C_H_ + +#include +#include +#include +#include +#include "fts_lib/ftsSoftware.h" +#include "fts_lib/ftsHardware.h" +#include +/****************** CONFIGURATION SECTION ******************/ +/** @defgroup conf_section Driver Configuration Section +* Settings of the driver code in order to suit the HW set up and the application behavior +* @{ +*/ + +/**** CODE CONFIGURATION ****/ +#define FTS_TS_DRV_NAME "fts" /*driver name*/ +#define FTS_TS_DRV_VERSION "5.2.4" /*driver version string format*/ +#define FTS_TS_DRV_VER 0x05020400 /*driver version u32 format*/ + +#define PINCTRL_STATE_ACTIVE "pmx_ts_active" +#define PINCTRL_STATE_SUSPEND "pmx_ts_suspend" +#define PINCTRL_STATE_RELEASE "pmx_ts_release" + + +#define DRIVER_TEST + +#define PRE_SAVED_METHOD + +/*#define FW_H_FILE*/ +#define FW_UPDATE_ON_PROBE +#ifdef FW_H_FILE +#define FW_SIZE_NAME myArray_size +#define FW_ARRAY_NAME myArray +#endif + +/*#define LIMITS_H_FILE*/ +#ifdef LIMITS_H_FILE +#define LIMITS_SIZE_NAME myArray2_size +#define LIMITS_ARRAY_NAME myArray2 +#endif + + +/*#define USE_ONE_FILE_NODE*/ + +#ifndef FW_UPDATE_ON_PROBE +#define EXP_FN_WORK_DELAY_MS 1000 +#endif + +/**** END ****/ + +/**** FEATURES USED IN THE IC ****/ + +/*#define PHONE_KEY*/ + +#define GESTURE_MODE +#ifdef GESTURE_MODE +#define USE_GESTURE_MASK +#endif + +#define CHARGER_MODE + +#define GLOVE_MODE + +#define COVER_MODE + +#define STYLUS_MODE + + +/**** END ****/ + +/**** PANEL SPECIFICATION ****/ +#define X_AXIS_MAX 1080 +#define X_AXIS_MIN 0 +#define Y_AXIS_MAX 2340 +#define Y_AXIS_MIN 0 + +#define PRESSURE_MIN 0 +#ifdef CONFIG_INPUT_PRESS_NDT +#define PRESSURE_MAX 2048 +#else +#define PRESSURE_MAX 127 +#endif + +#define DISTANCE_MIN 0 +#define DISTANCE_MAX 127 + +#define TOUCH_ID_MAX 10 + +#define AREA_MIN PRESSURE_MIN +#define AREA_MAX PRESSURE_MAX +/**** END ****/ +/**@}*/ +/*********************************************************/ + +/* + * Configuration mode + * + * bitmask which can assume the value defined as features in ftsSoftware.h or the following values + */ + +/** @defgroup mode_section IC Status Mode +* Bitmask which keeps track of the features and working mode enabled in the IC. +* The meaning of the the LSB of the bitmask must be interpreted considering that the value defined in @link feat_opt Feature Selection Option @endlink correspond to the position of the corresponding bit in the mask +* @{ +*/ +#define MODE_NOTHING 0x00000000 +#define MODE_ACTIVE(_mask, _sett)\ +do {\ + _mask |= (SCAN_MODE_ACTIVE << 24)|(_sett << 16);\ +} while (0) +#define MODE_LOW_POWER(_mask, _sett)\ +do {\ + _mask |= (SCAN_MODE_LOW_POWER << 24)|(_sett << 16);\ +} while (0) +/** @}*/ + +#define CMD_STR_LEN 32 + +#define TSP_BUF_SIZE PAGE_SIZE + +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP +#define TOUCH_COUNT_FILE_MAXSIZE 50 +#endif + +/** + * Struct which contains information about the HW platform and set up + */ +#define FTS_LOCKDOWN_SIZE 8 +#define FTS_RESULT_INVALID 0 +#define FTS_RESULT_PASS 2 +#define FTS_RESULT_FAIL 1 + +struct fts_config_info { + u8 tp_vendor; + u8 tp_color; + u8 tp_hw_version; + const char *fts_cfg_name; + const char *fts_limit_name; +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + const char *clicknum_file_name; +#endif +}; + +struct fts_hw_platform_data { + int (*power) (bool on); + int irq_gpio; + int reset_gpio; + unsigned long irq_flags; + unsigned int x_max; + unsigned int y_max; + const char *vdd_reg_name; + const char *avdd_reg_name; + const char *default_fw_name; + size_t config_array_size; + struct fts_config_info *config_array; + int current_index; +#ifdef PHONE_KEY + size_t nbuttons; + int *key_code; +#endif +#ifdef CONFIG_FTS_TOUCH_COUNT_DUMP + bool dump_click_count; +#endif + unsigned long keystates; +}; + +/* + * Forward declaration + */ +struct fts_ts_info; +extern char tag[8]; + +/* + * Dispatch event handler + */ +typedef void (*event_dispatch_handler_t) + (struct fts_ts_info *info, unsigned char *data); + +#ifdef CONFIG_SECURE_TOUCH +struct fts_secure_delay { + bool palm_pending; + int palm_value; +}; + +struct fts_secure_info { + bool secure_inited; + atomic_t st_1st_complete; + atomic_t st_enabled; + atomic_t st_pending_irqs; + struct completion st_irq_processed; + struct completion st_powerdown; + struct fts_secure_delay scr_delay; + struct mutex palm_lock; + void *fts_info; +}; +#endif + +#ifdef CONFIG_I2C_BY_DMA +struct fts_dma_buf { + struct mutex dmaBufLock; + u8 *rdBuf; + u8 *wrBuf; +}; +#endif + + +/** + * FTS capacitive touch screen device information + * - dev Pointer to the structure device \n + * - client client structure \n + * - input_dev Input device structure \n + * - work Work thread \n + * - event_wq Event queue for work thread \n + * - event_dispatch_table Event dispatch table handlers \n + * - attrs SysFS attributes \n + * - mode Device operating mode (bitmask) \n + * - touch_id Bitmask for touch id (mapped to input slots) \n + * - stylus_id Bitmask for tracking the stylus touches (mapped using the touchId) \n + * - timer Timer when operating in polling mode \n + * - power Power on/off routine \n + * - board HW info retrieved from device tree \n + * - vdd_reg DVDD power regulator \n + * - avdd_reg AVDD power regulator \n + * - resume_bit Indicate if screen off/on \n + * - fwupdate_stat Store the result of a fw update triggered by the host \n + * - notifier Used for be notified from a suspend/resume event \n + * - sensor_sleep true suspend was called, false resume was called \n + * - wakelock Wake Lock struct \n + * - input_report_mutex mutex for handling the pressure of keys \n + * - series_of_switches to store the enabling status of a particular feature from the host \n + */ +struct fts_ts_info { + struct device *dev; +#ifdef I2C_INTERFACE + struct i2c_client *client; +#else + struct spi_device *client; +#endif + struct input_dev *input_dev; + + struct work_struct work; + struct work_struct suspend_work; + struct work_struct resume_work; + struct work_struct mode_handler_work; + struct work_struct cmd_update_work; + struct work_struct sleep_work; + struct workqueue_struct *event_wq; + struct workqueue_struct *irq_wq; + struct workqueue_struct *touch_feature_wq; + +#ifndef FW_UPDATE_ON_PROBE + struct delayed_work fwu_work; + struct workqueue_struct *fwu_workqueue; +#endif + event_dispatch_handler_t *event_dispatch_table; + + struct attribute_group attrs; + + unsigned int mode; + unsigned long touch_id; + unsigned long touch_skip; + int coor[TOUCH_ID_MAX][2]; +#ifdef STYLUS_MODE + unsigned long stylus_id; +#endif + struct fts_hw_platform_data *board; + struct regulator *vdd_reg; + struct regulator *avdd_reg; + + int resume_bit; + int fwupdate_stat; + + struct notifier_block notifier; + struct notifier_block bl_notifier; + bool sensor_sleep; + bool sensor_scan; + struct pinctrl *ts_pinctrl; + struct pinctrl_state *pinctrl_state_active; + struct pinctrl_state *pinctrl_state_suspend; + u8 lockdown_info[FTS_LOCKDOWN_SIZE]; + int result_type; + struct proc_dir_entry *tp_selftest_proc; + struct proc_dir_entry *tp_data_dump_proc; + struct proc_dir_entry *tp_fw_version_proc; + struct proc_dir_entry *tp_lockdown_info_proc; + + /* input lock */ + struct mutex input_report_mutex; + int gesture_enabled; + int glove_enabled; + int charger_enabled; + int stylus_enabled; + int cover_enabled; + unsigned int grip_enabled; + unsigned int grip_pixel; + unsigned int doze_time; + unsigned int grip_pixel_def; + unsigned int doze_time_def; +#ifdef CONFIG_TOUCHSCREEN_ST_DEBUG_FS + struct dentry *debugfs; +#endif + struct class *fts_tp_class; + struct device *fts_touch_dev; + char *current_clicknum_file; +#ifdef CONFIG_SECURE_TOUCH + struct fts_secure_info *secure_info; +#endif +#ifdef CONFIG_I2C_BY_DMA + struct fts_dma_buf *dma_buf; +#endif + bool lockdown_is_ok; + bool irq_status; + wait_queue_head_t wait_queue; + struct completion tp_reset_completion; + atomic_t system_is_resetting; + unsigned int fod_status; + unsigned long fod_id; + struct mutex fod_mutex; + struct mutex cmd_update_mutex; + bool fod_status_set; + bool p_sensor_changed; + bool p_sensor_switch; + bool palm_sensor_changed; + bool palm_sensor_switch; + bool tp_pm_suspend; + struct completion pm_resume_completion; +}; + +struct fts_mode_switch { + struct fts_ts_info *info; + unsigned char mode; + struct work_struct switch_mode_work; +}; + +int fts_chip_powercycle(struct fts_ts_info *info); +extern int input_register_notifier_client(struct notifier_block *nb); +extern int input_unregister_notifier_client(struct notifier_block *nb); + +extern int fts_proc_init(void); +extern int fts_proc_remove(void); +#ifdef CONFIG_FTS_FOD_AREA_REPORT +#define CENTER_X 540 +#define CENTER_Y 2005 +#define CIRCLE_R 87 +#define FOD_LX 420 +#define FOD_LY 1885 +#define FOD_SIDE 242 +bool fts_is_infod(void); +void fts_get_pointer(int *touch_flag, int *x, int *y); +#endif +void fts_restore_regvalues(void); + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_fw.h b/drivers/input/touchscreen/fts_521/fts_fw.h new file mode 100644 index 000000000000..6821f3945a7b --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_fw.h @@ -0,0 +1,12573 @@ +/*! +* \file fts_fw.h +* \brief Contains the size and the byte array of the fw file to burn into the IC +*/ +#ifndef FTS_FW_H +#define FTS_FW_H +/*This is an auto generated header file*/ +/*--->Remember to change the name of the two variables!<---*/ +const uint32_t myArray_size = 100476; + +const uint8_t myArray[] = { + 0x55, 0xAA, 0x55, 0xAA, 0x01, 0x00, 0x00, 0x00, 0x36, 0x39, 0x00, 0x00, + 0x33, 0xA2, 0x00, 0x00, + 0x33, 0xA2, 0x00, 0x00, 0xA1, 0x00, 0xA1, 0x00, 0xA1, 0x00, 0xA1, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xE8, 0x7D, 0x01, 0x00, + 0x50, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xF3, 0xB0, 0x4F, 0xDA, + 0x69, 0xDA, 0x63, 0x91, 0x79, 0x5F, 0x00, 0x00, 0x96, 0x25, 0x9C, 0x6E, + 0x86, 0xA0, 0xFF, 0xFF, + 0x00, 0x04, 0x10, 0x00, 0xB5, 0x02, 0x00, 0x00, 0x0D, 0x03, 0x00, 0x00, + 0x27, 0x03, 0x00, 0x00, + 0x41, 0x03, 0x00, 0x00, 0x5B, 0x03, 0x00, 0x00, 0x75, 0x03, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x85, 0x6E, 0x01, 0x00, + 0x8D, 0x6E, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8F, 0x03, 0x00, 0x00, + 0x95, 0x6E, 0x01, 0x00, + 0x9D, 0x6E, 0x01, 0x00, 0xAB, 0x6E, 0x01, 0x00, 0xB9, 0x6E, 0x01, 0x00, + 0xC7, 0x6E, 0x01, 0x00, + 0xD5, 0x6E, 0x01, 0x00, 0xE3, 0x6E, 0x01, 0x00, 0xF1, 0x6E, 0x01, 0x00, + 0xFF, 0x6E, 0x01, 0x00, + 0x0D, 0x6F, 0x01, 0x00, 0x9D, 0x03, 0x00, 0x00, 0x1B, 0x6F, 0x01, 0x00, + 0x29, 0x6F, 0x01, 0x00, + 0x37, 0x6F, 0x01, 0x00, 0x3F, 0x6F, 0x01, 0x00, 0x47, 0x6F, 0x01, 0x00, + 0x4F, 0x6F, 0x01, 0x00, + 0x5D, 0x6F, 0x01, 0x00, 0x65, 0x6F, 0x01, 0x00, 0x6D, 0x6F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x75, 0x6F, 0x01, 0x00, + 0x7D, 0x6F, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x85, 0x6F, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x33, 0xA2, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0xF0, 0x02, 0xF8, 0x00, 0xF0, 0x68, 0xF8, 0x0A, 0xA0, 0x90, 0xE8, + 0x00, 0x0C, 0x82, 0x44, + 0x83, 0x44, 0xAA, 0xF1, 0x01, 0x07, 0xDA, 0x45, 0x01, 0xD1, 0x00, 0xF0, + 0x5D, 0xF8, 0xAF, 0xF2, + 0x09, 0x0E, 0xBA, 0xE8, 0x0F, 0x00, 0x13, 0xF0, 0x01, 0x0F, 0x18, 0xBF, + 0xFB, 0x1A, 0x43, 0xF0, + 0x01, 0x03, 0x18, 0x47, 0x1C, 0x7C, 0x01, 0x00, 0x4C, 0x7C, 0x01, 0x00, + 0x0A, 0x44, 0x4F, 0xF0, + 0x00, 0x0C, 0x10, 0xF8, 0x01, 0x3B, 0x13, 0xF0, 0x07, 0x04, 0x08, 0xBF, + 0x10, 0xF8, 0x01, 0x4B, + 0x1D, 0x11, 0x08, 0xBF, 0x10, 0xF8, 0x01, 0x5B, 0x64, 0x1E, 0x05, 0xD0, + 0x10, 0xF8, 0x01, 0x6B, + 0x64, 0x1E, 0x01, 0xF8, 0x01, 0x6B, 0xF9, 0xD1, 0x13, 0xF0, 0x08, 0x0F, + 0x1E, 0xBF, 0x10, 0xF8, + 0x01, 0x4B, 0xAD, 0x1C, 0x0C, 0x1B, 0x09, 0xD1, 0x6D, 0x1E, 0x58, 0xBF, + 0x01, 0xF8, 0x01, 0xCB, + 0xFA, 0xD5, 0x05, 0xE0, 0x14, 0xF8, 0x01, 0x6B, 0x01, 0xF8, 0x01, 0x6B, + 0x6D, 0x1E, 0xF9, 0xD5, + 0x91, 0x42, 0xD6, 0xD3, 0x70, 0x47, 0x00, 0x00, 0x10, 0x3A, 0x24, 0xBF, + 0x78, 0xC8, 0x78, 0xC1, + 0xFA, 0xD8, 0x52, 0x07, 0x24, 0xBF, 0x30, 0xC8, 0x30, 0xC1, 0x44, 0xBF, + 0x04, 0x68, 0x0C, 0x60, + 0x70, 0x47, 0x00, 0x00, 0x00, 0x23, 0x00, 0x24, 0x00, 0x25, 0x00, 0x26, + 0x10, 0x3A, 0x28, 0xBF, + 0x78, 0xC1, 0xFB, 0xD8, 0x52, 0x07, 0x28, 0xBF, 0x30, 0xC1, 0x48, 0xBF, + 0x0B, 0x60, 0x70, 0x47, + 0x1F, 0xB5, 0x1F, 0xBD, 0x10, 0xB5, 0x10, 0xBD, 0xDF, 0xF8, 0x0C, 0xD0, + 0xFF, 0xF7, 0xF8, 0xFF, + 0x16, 0xF0, 0xE4, 0xFE, 0x17, 0xF0, 0x69, 0xF8, 0x00, 0x04, 0x10, 0x00, + 0x03, 0xB4, 0xFF, 0xF7, + 0xF1, 0xFF, 0x03, 0xBC, 0x17, 0xF0, 0x68, 0xF8, 0x0A, 0x48, 0x4F, 0xF0, + 0xFF, 0x01, 0x01, 0x70, + 0x4F, 0xF0, 0x00, 0x00, 0x80, 0xF3, 0x11, 0x88, 0x4F, 0xF0, 0x00, 0x00, + 0x80, 0xF3, 0x09, 0x88, + 0x05, 0x48, 0x4F, 0xF0, 0x02, 0x01, 0x01, 0x70, 0x62, 0xB6, 0x04, 0x48, + 0x4F, 0xF0, 0x80, 0x51, + 0x01, 0x60, 0x70, 0x47, 0x22, 0xED, 0x00, 0xE0, 0x00, 0x04, 0x10, 0x00, + 0x04, 0xED, 0x00, 0xE0, + 0x02, 0x48, 0x4F, 0xF0, 0x80, 0x51, 0x01, 0x60, 0x70, 0x47, 0x00, 0x00, + 0x04, 0xED, 0x00, 0xE0, + 0x4F, 0xF0, 0x20, 0x00, 0x80, 0xF3, 0x11, 0x88, 0xEF, 0xF3, 0x09, 0x80, + 0x98, 0xB1, 0x12, 0x48, + 0x00, 0x68, 0x12, 0x49, 0x09, 0x68, 0x88, 0x42, 0x17, 0xD0, 0xEF, 0xF3, + 0x09, 0x80, 0x0E, 0x49, + 0x09, 0x68, 0x20, 0xE9, 0xF0, 0x0F, 0x88, 0x60, 0x00, 0xB5, 0x0B, 0x48, + 0x00, 0x68, 0x00, 0xF0, + 0x2F, 0xF9, 0x5D, 0xF8, 0x04, 0xEB, 0x08, 0x48, 0x08, 0x49, 0x0A, 0x68, + 0x02, 0x60, 0x00, 0x68, + 0x81, 0x68, 0xB1, 0xE8, 0xF0, 0x0F, 0x81, 0xF3, 0x09, 0x88, 0x4E, 0xF0, + 0x04, 0x0E, 0x4F, 0xF0, + 0x00, 0x00, 0x80, 0xF3, 0x11, 0x88, 0x70, 0x47, 0x04, 0x04, 0x10, 0x00, + 0x08, 0x04, 0x10, 0x00, + 0xEF, 0xF3, 0x11, 0x80, 0x4F, 0xF0, 0x20, 0x01, 0x81, 0xF3, 0x11, 0x88, + 0x70, 0x47, 0x00, 0x00, + 0x4F, 0xF0, 0x00, 0x00, 0x80, 0xF3, 0x11, 0x88, 0x70, 0x47, 0x00, 0x00, + 0x62, 0xB6, 0x70, 0x47, + 0x72, 0xB6, 0x70, 0x47, 0x40, 0x1E, 0xFD, 0xD1, 0x70, 0x47, 0x00, 0x00, + 0x40, 0xBA, 0x70, 0x47, + 0xC0, 0xBA, 0x70, 0x47, 0x12, 0x48, 0x13, 0x49, 0xA1, 0xEB, 0x00, 0x01, + 0x4F, 0xF0, 0x20, 0x03, + 0x91, 0xFB, 0xF3, 0xF2, 0x02, 0xFB, 0x13, 0x11, 0x4F, 0xF0, 0xCC, 0x33, + 0x4F, 0xF0, 0xCC, 0x34, + 0x4F, 0xF0, 0xCC, 0x35, 0x4F, 0xF0, 0xCC, 0x36, 0x4F, 0xF0, 0xCC, 0x37, + 0x4F, 0xF0, 0xCC, 0x38, + 0x4F, 0xF0, 0xCC, 0x39, 0x4F, 0xF0, 0xCC, 0x3A, 0xA0, 0xE8, 0xF8, 0x07, + 0x01, 0x3A, 0xFB, 0xD1, + 0x19, 0xB1, 0x40, 0xF8, 0x04, 0xAB, 0x04, 0x39, 0xFB, 0xD1, 0x03, 0x48, + 0x00, 0x47, 0x00, 0x00, + 0x00, 0x00, 0x10, 0x00, 0x00, 0x04, 0x10, 0x00, 0xE1, 0x00, 0x00, 0x00, + 0x1E, 0xF0, 0x04, 0x0F, + 0x0C, 0xBF, 0xEF, 0xF3, 0x08, 0x80, 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, + 0x01, 0x01, 0x4F, 0xF0, + 0x00, 0x02, 0x12, 0xF0, 0xBB, 0xB8, 0x1E, 0xF0, 0x04, 0x0F, 0x0C, 0xBF, + 0xEF, 0xF3, 0x08, 0x80, + 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, 0x02, 0x01, 0x4F, 0xF0, 0x00, 0x02, + 0x12, 0xF0, 0xAE, 0xB8, + 0x1E, 0xF0, 0x04, 0x0F, 0x0C, 0xBF, 0xEF, 0xF3, 0x08, 0x80, 0xEF, 0xF3, + 0x09, 0x80, 0x4F, 0xF0, + 0x03, 0x01, 0x4F, 0xF0, 0x00, 0x02, 0x12, 0xF0, 0xA1, 0xB8, 0x1E, 0xF0, + 0x04, 0x0F, 0x0C, 0xBF, + 0xEF, 0xF3, 0x08, 0x80, 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, 0x04, 0x01, + 0x4F, 0xF0, 0x00, 0x02, + 0x12, 0xF0, 0x94, 0xB8, 0x1E, 0xF0, 0x04, 0x0F, 0x0C, 0xBF, 0xEF, 0xF3, + 0x08, 0x80, 0xEF, 0xF3, + 0x09, 0x80, 0x4F, 0xF0, 0x05, 0x01, 0x4F, 0xF0, 0x00, 0x02, 0x12, 0xF0, + 0x87, 0xB8, 0x00, 0xB5, + 0x16, 0xF0, 0x72, 0xFD, 0x5D, 0xF8, 0x04, 0xEB, 0xFF, 0xF7, 0x42, 0xBF, + 0x1E, 0xF0, 0x04, 0x0F, + 0x0C, 0xBF, 0xEF, 0xF3, 0x08, 0x80, 0xEF, 0xF3, 0x09, 0x80, 0x4F, 0xF0, + 0x06, 0x01, 0x4F, 0xF0, + 0x00, 0x02, 0x12, 0xF0, 0x73, 0xB8, 0x00, 0x00, 0x19, 0x49, 0x10, 0xB5, + 0x01, 0x20, 0x08, 0x70, + 0x18, 0x49, 0x00, 0x20, 0x08, 0x60, 0x18, 0x49, 0x08, 0x60, 0x18, 0x49, + 0x08, 0x60, 0x18, 0x49, + 0x08, 0x60, 0x00, 0xF0, 0xBF, 0xF9, 0x00, 0xF0, 0x59, 0xF9, 0x00, 0xF0, + 0x7D, 0xF8, 0x00, 0x20, + 0x10, 0xBD, 0x10, 0xB5, 0x11, 0x48, 0x00, 0xF0, 0x38, 0xF9, 0x0F, 0x49, + 0x08, 0x60, 0x0D, 0x49, + 0x09, 0x68, 0x88, 0x42, 0x07, 0xD0, 0x0A, 0x48, 0x00, 0x78, 0x02, 0x28, + 0x03, 0xD1, 0xBD, 0xE8, + 0x10, 0x40, 0xFF, 0xF7, 0x05, 0xBF, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, + 0xEA, 0xFF, 0x04, 0x49, + 0x02, 0x20, 0x08, 0x70, 0xFF, 0xF7, 0xE0, 0xFE, 0x4F, 0xF0, 0xFF, 0x30, + 0x10, 0xBD, 0x00, 0x00, + 0x00, 0x04, 0x10, 0x00, 0x04, 0x04, 0x10, 0x00, 0x08, 0x04, 0x10, 0x00, + 0x0C, 0x04, 0x10, 0x00, + 0x10, 0x04, 0x10, 0x00, 0x70, 0xB5, 0x0D, 0x46, 0x04, 0x46, 0xC1, 0x69, + 0x80, 0x68, 0xCC, 0x22, + 0x16, 0xF0, 0xDA, 0xFE, 0xE1, 0x69, 0xA0, 0x68, 0x08, 0x44, 0x4F, 0xF0, + 0x80, 0x71, 0x40, 0xF8, + 0x04, 0x1C, 0x21, 0x6A, 0x40, 0xF8, 0x08, 0x1C, 0x00, 0x21, 0x40, 0xF8, + 0x0C, 0x1C, 0x40, 0xF8, + 0x10, 0x1C, 0x40, 0xF8, 0x14, 0x1C, 0x40, 0xF8, 0x18, 0x1C, 0x40, 0xE9, + 0x08, 0x51, 0x4F, 0xF0, + 0x0B, 0x31, 0x40, 0xF8, 0x24, 0x1C, 0x4F, 0xF0, 0x0A, 0x31, 0x40, 0xF8, + 0x28, 0x1C, 0x4F, 0xF0, + 0x09, 0x31, 0x40, 0xF8, 0x2C, 0x1C, 0x4F, 0xF0, 0x08, 0x31, 0x40, 0xF8, + 0x30, 0x1C, 0x4F, 0xF0, + 0x07, 0x31, 0x40, 0xF8, 0x34, 0x1C, 0x4F, 0xF0, 0x06, 0x31, 0x40, 0xF8, + 0x38, 0x1C, 0x4F, 0xF0, + 0x05, 0x31, 0x40, 0xF8, 0x3C, 0x1C, 0x4F, 0xF0, 0x04, 0x31, 0x40, 0xF8, + 0x40, 0x1D, 0x70, 0xBD, + 0x81, 0x69, 0x4F, 0xF0, 0xCC, 0x32, 0x0B, 0x68, 0x93, 0x42, 0x08, 0xD1, + 0x4B, 0x68, 0x93, 0x42, + 0x05, 0xD1, 0x8B, 0x68, 0x93, 0x42, 0x02, 0xD1, 0xC9, 0x68, 0x91, 0x42, + 0x02, 0xD0, 0x40, 0x68, + 0x12, 0xF0, 0xD9, 0xBB, 0x70, 0x47, 0x00, 0x00, 0x10, 0xB5, 0xA0, 0x21, + 0x49, 0x48, 0x16, 0xF0, + 0xB5, 0xFE, 0x00, 0x20, 0x10, 0xBD, 0x70, 0xB5, 0x05, 0x46, 0x46, 0x48, + 0x00, 0xEB, 0x05, 0x14, + 0xFF, 0xF7, 0xC6, 0xFE, 0x06, 0x46, 0x20, 0x78, 0x28, 0xB1, 0x30, 0x46, + 0xFF, 0xF7, 0xC8, 0xFE, + 0x6F, 0xF0, 0x01, 0x00, 0x70, 0xBD, 0x03, 0x20, 0x20, 0x70, 0x00, 0x20, + 0x65, 0x60, 0xE0, 0x60, + 0x04, 0xF1, 0x08, 0x00, 0x00, 0xF0, 0x7A, 0xF8, 0x30, 0x46, 0xFF, 0xF7, + 0xB9, 0xFE, 0x00, 0x20, + 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x0F, 0x46, 0x36, 0x49, 0x00, 0x25, + 0x01, 0xEB, 0x00, 0x14, + 0x2E, 0x46, 0xFF, 0xF7, 0xA5, 0xFE, 0x80, 0x46, 0xE0, 0x68, 0x38, 0x43, + 0xE0, 0x60, 0x04, 0xF1, + 0x08, 0x00, 0x07, 0x46, 0x00, 0xF0, 0x89, 0xF8, 0x0C, 0xE0, 0xE1, 0x68, + 0xC2, 0x6A, 0x11, 0x42, + 0x03, 0xD0, 0x00, 0xF0, 0x4F, 0xF9, 0x01, 0x26, 0x00, 0xE0, 0x6D, 0x1C, + 0x29, 0x46, 0x38, 0x46, + 0x00, 0xF0, 0x71, 0xF8, 0x00, 0x28, 0xF0, 0xD1, 0x0E, 0xB1, 0xFF, 0xF7, + 0x3A, 0xFF, 0x40, 0x46, + 0xFF, 0xF7, 0x8E, 0xFE, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x70, 0xB5, + 0x0D, 0x46, 0x21, 0x49, + 0x01, 0xEB, 0x00, 0x14, 0xFF, 0xF7, 0x7C, 0xFE, 0xE1, 0x68, 0xA9, 0x43, + 0xE1, 0x60, 0xFF, 0xF7, + 0x7F, 0xFE, 0x00, 0x20, 0x70, 0xBD, 0x70, 0xB5, 0x0C, 0x46, 0x1A, 0x49, + 0x01, 0xEB, 0x00, 0x15, + 0x00, 0x20, 0x20, 0x60, 0xFF, 0xF7, 0x6C, 0xFE, 0xE9, 0x68, 0x21, 0x60, + 0xFF, 0xF7, 0x70, 0xFE, + 0x00, 0x20, 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x0D, 0x46, 0x12, 0x49, + 0x1E, 0x46, 0x90, 0x46, + 0x01, 0xEB, 0x00, 0x14, 0xFF, 0xF7, 0x5C, 0xFE, 0x07, 0x46, 0x0F, 0x48, + 0x00, 0x68, 0xC5, 0x62, + 0xE1, 0x68, 0x29, 0x42, 0x03, 0xD1, 0x04, 0xF1, 0x08, 0x01, 0x00, 0xF0, + 0x1D, 0xF9, 0x38, 0x46, + 0xFF, 0xF7, 0x56, 0xFE, 0xFF, 0xF7, 0x4C, 0xFE, 0xE1, 0x68, 0x29, 0x40, + 0x31, 0x60, 0xB8, 0xF1, + 0x01, 0x0F, 0x02, 0xD1, 0xE1, 0x68, 0xA9, 0x43, 0xE1, 0x60, 0xFF, 0xF7, + 0x49, 0xFE, 0x00, 0x20, + 0xB9, 0xE7, 0x00, 0x00, 0x0C, 0x08, 0x10, 0x00, 0x04, 0x04, 0x10, 0x00, + 0x00, 0x21, 0x01, 0x60, + 0x08, 0x46, 0x70, 0x47, 0x30, 0xB5, 0x0A, 0x68, 0x12, 0xB1, 0x0B, 0x46, + 0x84, 0x6A, 0x09, 0xE0, + 0x00, 0x22, 0x08, 0x60, 0xC0, 0xE9, 0x03, 0x21, 0x0B, 0xE0, 0x00, 0xBF, + 0x02, 0xF1, 0x0C, 0x03, + 0xD2, 0x68, 0x12, 0xB1, 0x95, 0x6A, 0xA5, 0x42, 0xF8, 0xDC, 0x1A, 0x68, + 0xC0, 0xE9, 0x03, 0x21, + 0x18, 0x60, 0x00, 0x20, 0x30, 0xBD, 0x00, 0x68, 0x00, 0x22, 0x01, 0xE0, + 0xC0, 0x68, 0x52, 0x1C, + 0x8A, 0x42, 0x01, 0xD0, 0x00, 0x28, 0xF9, 0xD1, 0x70, 0x47, 0x00, 0x68, + 0x70, 0x47, 0x02, 0x69, + 0x0A, 0xB1, 0x11, 0x68, 0x31, 0xB9, 0x6F, 0xF0, 0x04, 0x00, 0x70, 0x47, + 0x01, 0xF1, 0x0C, 0x02, + 0xC9, 0x68, 0x39, 0xB1, 0x81, 0x42, 0xF9, 0xD1, 0xC9, 0x68, 0x11, 0x60, + 0x00, 0x21, 0x01, 0x61, + 0x08, 0x46, 0x70, 0x47, 0x6F, 0xF0, 0x03, 0x00, 0x70, 0x47, 0x00, 0x00, + 0x10, 0xB5, 0xC8, 0x21, + 0x2E, 0x48, 0x16, 0xF0, 0xDB, 0xFD, 0x00, 0x20, 0x10, 0xBD, 0x2D, 0xE9, + 0xF0, 0x41, 0x05, 0x46, + 0x2A, 0x49, 0x00, 0xEB, 0x85, 0x00, 0x17, 0x46, 0x01, 0xEB, 0x80, 0x04, + 0xFF, 0xF7, 0xE8, 0xFD, + 0x06, 0x46, 0x20, 0x78, 0x30, 0xB1, 0x30, 0x46, 0xFF, 0xF7, 0xEA, 0xFD, + 0x6F, 0xF0, 0x01, 0x00, + 0xBD, 0xE8, 0xF0, 0x81, 0x02, 0x20, 0x20, 0x70, 0x00, 0x20, 0x65, 0x60, + 0xC4, 0xE9, 0x02, 0x70, + 0x04, 0xF1, 0x10, 0x00, 0xFF, 0xF7, 0x9A, 0xFF, 0x30, 0x46, 0xFF, 0xF7, + 0xD9, 0xFD, 0x00, 0x20, + 0xEE, 0xE7, 0x70, 0xB5, 0x19, 0x49, 0x00, 0xEB, 0x80, 0x00, 0x01, 0xEB, + 0x80, 0x04, 0xFF, 0xF7, + 0xC7, 0xFD, 0x05, 0x46, 0xD4, 0xE9, 0x02, 0x01, 0x81, 0x42, 0x05, 0xDB, + 0x14, 0x48, 0x04, 0xF1, + 0x10, 0x01, 0x00, 0x68, 0x00, 0xF0, 0x88, 0xF8, 0xE0, 0x68, 0x40, 0x1C, + 0xE0, 0x60, 0x28, 0x46, + 0xFF, 0xF7, 0xBE, 0xFD, 0x00, 0x20, 0x70, 0xBD, 0x70, 0xB5, 0x0C, 0x49, + 0x00, 0xEB, 0x80, 0x00, + 0x01, 0xEB, 0x80, 0x04, 0xFF, 0xF7, 0xAC, 0xFD, 0x05, 0x46, 0xE0, 0x68, + 0x08, 0xB1, 0x40, 0x1E, + 0xE0, 0x60, 0x04, 0xF1, 0x10, 0x00, 0xFF, 0xF7, 0x90, 0xFF, 0x10, 0xB1, + 0x20, 0x69, 0x00, 0xF0, + 0x11, 0xF8, 0x28, 0x46, 0xFF, 0xF7, 0xA4, 0xFD, 0x00, 0x20, 0x70, 0xBD, + 0xAC, 0x08, 0x10, 0x00, + 0x04, 0x04, 0x10, 0x00, 0x10, 0xB5, 0x4F, 0xF4, 0xF0, 0x71, 0x3C, 0x48, + 0x16, 0xF0, 0x76, 0xFD, + 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x04, 0x46, 0x90, 0xF8, 0x24, 0x00, + 0x02, 0x28, 0x0B, 0xD0, + 0x20, 0x46, 0xFF, 0xF7, 0x74, 0xFF, 0x02, 0x20, 0x84, 0xF8, 0x24, 0x00, + 0x34, 0x49, 0x20, 0x46, + 0xFF, 0xF7, 0x48, 0xFF, 0xFF, 0xF7, 0x2D, 0xFE, 0x00, 0x20, 0x10, 0xBD, + 0x2D, 0xE9, 0xF0, 0x5F, + 0x06, 0x46, 0x0A, 0xA8, 0x06, 0xEB, 0x46, 0x01, 0x90, 0xE8, 0x00, 0x0E, + 0x2B, 0x48, 0x1D, 0x46, + 0x00, 0xEB, 0x01, 0x14, 0x90, 0x46, 0x20, 0x78, 0x18, 0xB1, 0x6F, 0xF0, + 0x01, 0x00, 0xBD, 0xE8, + 0xF0, 0x9F, 0xFF, 0xF7, 0x65, 0xFD, 0x07, 0x46, 0x01, 0x20, 0x20, 0x70, + 0xC4, 0xF8, 0x14, 0x80, + 0xC4, 0xE9, 0x01, 0x65, 0x04, 0xF1, 0x18, 0x01, 0x00, 0x20, 0x81, 0xE8, + 0x20, 0x06, 0x84, 0xF8, + 0x24, 0x00, 0xE0, 0x60, 0x20, 0x61, 0xC4, 0xE9, 0x0A, 0x80, 0x59, 0x46, + 0x20, 0x46, 0xFF, 0xF7, + 0x29, 0xFE, 0xA0, 0x60, 0x20, 0x46, 0xFF, 0xF7, 0xBD, 0xFF, 0x38, 0x46, + 0xFF, 0xF7, 0x50, 0xFD, + 0x00, 0x20, 0xDC, 0xE7, 0x10, 0xB5, 0x04, 0x46, 0x90, 0xF8, 0x24, 0x00, + 0x02, 0x28, 0x09, 0xD0, + 0x20, 0x46, 0xFF, 0xF7, 0x2C, 0xFF, 0x02, 0x20, 0x84, 0xF8, 0x24, 0x00, + 0x10, 0x49, 0x20, 0x46, + 0xFF, 0xF7, 0x00, 0xFF, 0x00, 0x20, 0x10, 0xBD, 0x70, 0xB5, 0x04, 0x46, + 0x90, 0xF8, 0x24, 0x00, + 0x0D, 0x46, 0x02, 0x28, 0x0B, 0xD1, 0x20, 0x46, 0xFF, 0xF7, 0x19, 0xFF, + 0x03, 0x20, 0x84, 0xF8, + 0x24, 0x00, 0x29, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0xED, 0xFE, 0xFF, 0xF7, + 0xD2, 0xFD, 0x00, 0x20, + 0x70, 0xBD, 0x04, 0x48, 0x00, 0x68, 0x40, 0x68, 0x70, 0x47, 0x00, 0x00, + 0x74, 0x09, 0x10, 0x00, + 0x0C, 0x04, 0x10, 0x00, 0x04, 0x04, 0x10, 0x00, 0xA4, 0x22, 0x4F, 0x49, + 0x16, 0xF0, 0x55, 0xBC, + 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, 0x80, 0x07, 0x02, 0xD0, 0x02, 0x20, + 0x16, 0xF0, 0xA3, 0xF8, + 0x4F, 0xF4, 0x80, 0x30, 0x20, 0x44, 0xC0, 0xF3, 0x4F, 0x00, 0x10, 0xBD, + 0x01, 0x46, 0xAC, 0x22, + 0x46, 0x48, 0x16, 0xF0, 0x87, 0xBC, 0x45, 0x4A, 0x5F, 0xF0, 0x00, 0x01, + 0x42, 0xF8, 0x21, 0x00, + 0x49, 0x1C, 0x26, 0x29, 0xFA, 0xDB, 0x70, 0x47, 0x00, 0xF0, 0xF6, 0xBE, + 0x00, 0xF0, 0x1B, 0xBF, + 0x1D, 0x20, 0x70, 0x47, 0x26, 0x20, 0x70, 0x47, 0x3D, 0x48, 0x10, 0xB5, + 0x00, 0x68, 0x10, 0xB1, + 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x47, 0x00, 0x20, 0x16, 0xF0, 0x7D, 0xF8, + 0x10, 0xBD, 0x01, 0x29, + 0x12, 0xD0, 0x02, 0x29, 0x24, 0xD0, 0x03, 0x29, 0x0E, 0xD0, 0x04, 0x29, + 0x1D, 0xD1, 0x01, 0x78, + 0x21, 0xF0, 0x12, 0x01, 0x00, 0xF8, 0x35, 0x1B, 0x01, 0x7E, 0x21, 0xF0, + 0x03, 0x01, 0x01, 0x76, + 0xC1, 0x7F, 0x21, 0xF0, 0x80, 0x01, 0x22, 0xE0, 0x02, 0x78, 0x01, 0x29, + 0x42, 0xF0, 0x12, 0x02, + 0x02, 0x70, 0x0B, 0xD0, 0x5F, 0xF0, 0x03, 0x02, 0x10, 0xF8, 0x4D, 0x1F, + 0x62, 0xF3, 0x01, 0x01, + 0x01, 0x70, 0xC1, 0x79, 0x41, 0xF0, 0x80, 0x01, 0xC1, 0x71, 0x70, 0x47, + 0x01, 0x22, 0xF3, 0xE7, + 0x01, 0x78, 0x21, 0xF0, 0x02, 0x01, 0x41, 0xF0, 0x10, 0x01, 0x00, 0xF8, + 0x35, 0x1B, 0x01, 0x7E, + 0x21, 0xF0, 0x03, 0x01, 0x89, 0x1C, 0x01, 0x76, 0xC1, 0x7F, 0x41, 0xF0, + 0x80, 0x01, 0xC1, 0x77, + 0x70, 0x47, 0x90, 0xF8, 0x29, 0x20, 0x02, 0x29, 0x04, 0xD0, 0x03, 0x29, + 0x22, 0xF0, 0x40, 0x01, + 0x02, 0xD1, 0x04, 0xE0, 0x42, 0xF0, 0x40, 0x01, 0x21, 0xF0, 0x80, 0x01, + 0x01, 0xE0, 0x41, 0xF0, + 0x80, 0x01, 0x80, 0xF8, 0x29, 0x10, 0x70, 0x47, 0x90, 0xF8, 0x29, 0x20, + 0x01, 0x29, 0x04, 0xD0, + 0x02, 0x29, 0x07, 0xD0, 0x22, 0xF0, 0x10, 0x01, 0x01, 0xE0, 0x42, 0xF0, + 0x10, 0x01, 0x21, 0xF0, + 0x20, 0x01, 0x01, 0xE0, 0x42, 0xF0, 0x30, 0x01, 0x80, 0xF8, 0x29, 0x10, + 0x70, 0x47, 0xC2, 0x78, + 0x00, 0x29, 0x61, 0xF3, 0x03, 0x02, 0xC2, 0x70, 0x04, 0xD0, 0x10, 0xF8, + 0x5E, 0x1F, 0x41, 0xF0, + 0x04, 0x01, 0x01, 0x70, 0x70, 0x47, 0x00, 0x00, 0x48, 0x74, 0x01, 0x00, + 0xA4, 0x00, 0x03, 0x20, + 0x18, 0x04, 0x10, 0x00, 0x01, 0xEB, 0x81, 0x01, 0x02, 0xEB, 0xC1, 0x01, + 0x40, 0x5C, 0x01, 0x06, + 0x02, 0xD5, 0x00, 0xF0, 0x7F, 0x00, 0x40, 0x42, 0x70, 0x47, 0x00, 0x2B, + 0x04, 0xDA, 0x5B, 0x42, + 0xDB, 0xB2, 0x43, 0xF0, 0x80, 0x03, 0x01, 0xE0, 0x03, 0xF0, 0x7F, 0x03, + 0x01, 0xEB, 0x81, 0x01, + 0x02, 0xEB, 0xC1, 0x01, 0x43, 0x54, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x5F, + 0x00, 0x25, 0x17, 0x46, + 0x98, 0x46, 0x89, 0x46, 0x83, 0x46, 0x2E, 0x46, 0x4F, 0xF0, 0x01, 0x0A, + 0x0A, 0xFA, 0x05, 0xF0, + 0x10, 0xEA, 0x09, 0x0F, 0x14, 0xD0, 0x00, 0x24, 0x22, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x16, 0xF0, + 0x4D, 0xFB, 0x38, 0x40, 0x01, 0xEA, 0x08, 0x01, 0x08, 0x43, 0x05, 0xD0, + 0x00, 0x23, 0x22, 0x46, + 0x31, 0x46, 0x58, 0x46, 0xFF, 0xF7, 0xD1, 0xFF, 0x64, 0x1C, 0x26, 0x2C, + 0xEC, 0xDB, 0x76, 0x1C, + 0x6D, 0x1C, 0x1D, 0x2D, 0xE2, 0xDB, 0xBD, 0xE8, 0xF0, 0x9F, 0x40, 0x5C, + 0x01, 0x06, 0x02, 0xD5, + 0x00, 0xF0, 0x7F, 0x00, 0x40, 0x42, 0x70, 0x47, 0x00, 0x2A, 0x04, 0xDA, + 0x52, 0x42, 0xD2, 0xB2, + 0x42, 0xF0, 0x80, 0x02, 0x01, 0xE0, 0x02, 0xF0, 0x7F, 0x02, 0x42, 0x54, + 0x70, 0x47, 0xF0, 0xB5, + 0x00, 0x24, 0x16, 0x46, 0x0F, 0x46, 0x84, 0x46, 0x23, 0x46, 0x01, 0x25, + 0x10, 0xE0, 0x00, 0xBF, + 0x07, 0xEB, 0xE3, 0x00, 0x03, 0xF0, 0x07, 0x02, 0x01, 0x78, 0x05, 0xFA, + 0x02, 0xF0, 0x08, 0x42, + 0x05, 0xD0, 0x00, 0x22, 0x19, 0x46, 0x60, 0x46, 0xFF, 0xF7, 0xDE, 0xFF, + 0x64, 0x1C, 0x5B, 0x1C, + 0xB4, 0x42, 0xED, 0xDB, 0xF0, 0xBD, 0x40, 0x5C, 0x70, 0x47, 0x42, 0x54, + 0x70, 0x47, 0x00, 0x00, + 0x2D, 0xE9, 0xF0, 0x47, 0x34, 0x4C, 0x54, 0xF8, 0x3C, 0x8F, 0x67, 0x68, + 0xE6, 0x68, 0x25, 0x7C, + 0xDF, 0xF8, 0xC8, 0x90, 0x01, 0x21, 0xC9, 0xF8, 0x00, 0x10, 0x4F, 0xF4, + 0x20, 0x70, 0xFF, 0xF7, + 0xF9, 0xFB, 0x00, 0x21, 0xC9, 0xF8, 0x00, 0x10, 0xC4, 0xF8, 0x00, 0x80, + 0x67, 0x60, 0xE6, 0x60, + 0x25, 0x74, 0xBD, 0xE8, 0xF0, 0x87, 0x28, 0x48, 0x00, 0x21, 0xC1, 0x63, + 0x01, 0x64, 0x81, 0x64, + 0x80, 0xF8, 0x4C, 0x10, 0x70, 0x47, 0x10, 0xB5, 0x02, 0x46, 0x00, 0x24, + 0x4F, 0xF0, 0x01, 0x00, + 0x49, 0xB3, 0x00, 0x21, 0x16, 0xF0, 0xDA, 0xFA, 0x1F, 0x4A, 0x48, 0x32, + 0x10, 0x60, 0x11, 0x71, + 0xFF, 0xF7, 0xCE, 0xFF, 0x00, 0x20, 0x00, 0xF0, 0x25, 0xF8, 0x00, 0xB1, + 0x01, 0x24, 0xFF, 0xF7, + 0xC7, 0xFF, 0x01, 0x20, 0x00, 0xF0, 0x1E, 0xF8, 0x08, 0xB1, 0x44, 0xF0, + 0x02, 0x04, 0xFF, 0xF7, + 0xBF, 0xFF, 0x02, 0x20, 0x00, 0xF0, 0x16, 0xF8, 0x08, 0xB1, 0x44, 0xF0, + 0x04, 0x04, 0xFF, 0xF7, + 0xB7, 0xFF, 0x03, 0x20, 0x00, 0xF0, 0x0E, 0xF8, 0x08, 0xB1, 0x44, 0xF0, + 0x08, 0x04, 0xFF, 0xF7, + 0xAF, 0xFF, 0x20, 0x46, 0x10, 0xBD, 0x90, 0x40, 0x0B, 0x4A, 0x00, 0x21, + 0x3C, 0x32, 0xC2, 0xE9, + 0x00, 0x01, 0xD5, 0xE7, 0x40, 0xF0, 0x20, 0x01, 0x07, 0x48, 0x10, 0xB5, + 0x80, 0xF8, 0xA3, 0x10, + 0xE5, 0x21, 0x81, 0x71, 0x4F, 0xF4, 0x20, 0x70, 0xFF, 0xF7, 0xA4, 0xFB, + 0x04, 0x48, 0xD0, 0xF8, + 0xC0, 0x02, 0xC0, 0xB2, 0x10, 0xBD, 0x00, 0x00, 0x00, 0x00, 0x03, 0x20, + 0x68, 0x14, 0x60, 0x22, + 0x00, 0x10, 0x60, 0x22, 0x01, 0x49, 0x01, 0x20, 0x09, 0x68, 0x08, 0x47, + 0x1C, 0x04, 0x10, 0x00, + 0x10, 0xB5, 0xFF, 0xF7, 0x8B, 0xFE, 0x05, 0x49, 0x02, 0x20, 0x08, 0x70, + 0x04, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x04, 0x49, 0x09, 0x68, 0xBD, 0xE8, 0x10, 0x40, 0x08, 0x47, + 0x14, 0x04, 0x10, 0x00, + 0x18, 0x04, 0x10, 0x00, 0x1C, 0x04, 0x10, 0x00, 0x37, 0xB5, 0x04, 0x46, + 0x37, 0x49, 0x01, 0x98, + 0x15, 0x46, 0x08, 0x40, 0x01, 0x90, 0x04, 0x21, 0x01, 0xA8, 0x00, 0xF0, + 0xFC, 0xFA, 0x01, 0x2D, + 0x02, 0xD0, 0x02, 0x2D, 0x04, 0xD0, 0x06, 0xE0, 0xC0, 0x1C, 0x20, 0xF0, + 0x01, 0x00, 0x02, 0xE0, + 0xC0, 0x1D, 0x20, 0xF0, 0x03, 0x00, 0x01, 0x99, 0x44, 0xF8, 0x3C, 0x1F, + 0x00, 0x21, 0x61, 0x60, + 0x21, 0x7A, 0x60, 0xF3, 0x06, 0x01, 0x21, 0x72, 0x3E, 0xBD, 0x01, 0x23, + 0x40, 0xF8, 0x3C, 0x3F, + 0x00, 0x23, 0x43, 0x60, 0x51, 0x43, 0x02, 0x7A, 0x61, 0xF3, 0x06, 0x02, + 0x02, 0x72, 0x70, 0x47, + 0x1F, 0xB5, 0x04, 0x46, 0x03, 0x99, 0x02, 0xA8, 0x01, 0xF0, 0x3F, 0x01, + 0x03, 0x91, 0x08, 0x21, + 0x00, 0xF0, 0xD1, 0xFA, 0xDD, 0xE9, 0x02, 0x12, 0xA1, 0x64, 0x84, 0xF8, + 0x4C, 0x20, 0x14, 0xF8, + 0x70, 0x1F, 0x60, 0xF3, 0x05, 0x01, 0x04, 0xF8, 0x1E, 0x19, 0xE1, 0x7F, + 0x60, 0xF3, 0x05, 0x01, + 0xE1, 0x77, 0x1F, 0xBD, 0x08, 0xB5, 0x16, 0xA2, 0x12, 0x68, 0x00, 0x92, + 0x1D, 0xF8, 0x01, 0x20, + 0x10, 0xF8, 0x5D, 0x1F, 0x62, 0xF3, 0x01, 0x01, 0x01, 0x70, 0x08, 0xBD, + 0x10, 0xB5, 0x82, 0x79, + 0x22, 0xF0, 0x0D, 0x02, 0x42, 0xF0, 0xE0, 0x02, 0x82, 0x71, 0x0E, 0x4A, + 0x11, 0x60, 0x0E, 0x4A, + 0x03, 0x21, 0x11, 0x70, 0x0E, 0x4A, 0x0D, 0x49, 0x11, 0x60, 0x01, 0x46, + 0xA4, 0x22, 0x0D, 0x48, + 0x16, 0xF0, 0x4B, 0xFA, 0x0C, 0x49, 0x01, 0x20, 0xC1, 0xF8, 0xC0, 0x00, + 0xBD, 0xE8, 0x10, 0x40, + 0x0A, 0x49, 0x4F, 0xF4, 0xFA, 0x70, 0xFF, 0xF7, 0x07, 0xBE, 0x00, 0x00, + 0xFF, 0xFF, 0x03, 0x1C, + 0x00, 0x01, 0x02, 0x00, 0x1C, 0x04, 0x10, 0x00, 0x14, 0x04, 0x10, 0x00, + 0x81, 0x0B, 0x00, 0x00, + 0x18, 0x04, 0x10, 0x00, 0x00, 0x00, 0x03, 0x20, 0x00, 0x00, 0x60, 0x22, + 0x75, 0x0B, 0x00, 0x00, + 0x16, 0x48, 0x01, 0x78, 0x01, 0x29, 0x08, 0xD1, 0x02, 0x21, 0x01, 0x70, + 0x14, 0x48, 0x01, 0x68, + 0x19, 0xB1, 0x00, 0x22, 0x02, 0x60, 0x10, 0x46, 0x08, 0x47, 0x01, 0x20, + 0x15, 0xF0, 0x73, 0xBE, + 0x0E, 0x4A, 0x01, 0x21, 0x11, 0x70, 0x0E, 0x49, 0x08, 0x60, 0x0E, 0x49, + 0xE8, 0x20, 0x88, 0x71, + 0x0D, 0x49, 0x02, 0x20, 0xFF, 0xF7, 0xD8, 0xBD, 0x0A, 0x49, 0x08, 0x20, + 0x88, 0x71, 0x0B, 0x49, + 0x00, 0x20, 0x08, 0x62, 0x05, 0x49, 0x08, 0x70, 0x05, 0x49, 0x08, 0x60, + 0x70, 0x47, 0x03, 0x48, + 0x00, 0x78, 0x00, 0x28, 0x00, 0xD0, 0x01, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x14, 0x04, 0x10, 0x00, + 0x20, 0x04, 0x10, 0x00, 0x00, 0x00, 0x03, 0x20, 0xB1, 0x0C, 0x00, 0x00, + 0x00, 0x00, 0x60, 0x22, + 0x53, 0x49, 0x01, 0x20, 0x09, 0x68, 0x08, 0x47, 0x10, 0xB5, 0xFF, 0xF7, + 0xB7, 0xFD, 0x51, 0x49, + 0x02, 0x20, 0x08, 0x70, 0x50, 0x49, 0x00, 0x20, 0x08, 0x60, 0x4D, 0x49, + 0x09, 0x68, 0xBD, 0xE8, + 0x10, 0x40, 0x08, 0x47, 0x13, 0xB5, 0x04, 0x46, 0x4C, 0x49, 0x01, 0x98, + 0x08, 0x40, 0x01, 0x90, + 0x04, 0x21, 0x01, 0xA8, 0x00, 0xF0, 0x2F, 0xFA, 0x01, 0x99, 0x44, 0xF8, + 0x3C, 0x1F, 0x00, 0x21, + 0x61, 0x60, 0x14, 0xF8, 0x08, 0x1F, 0x60, 0xF3, 0x06, 0x01, 0x04, 0xF8, + 0x11, 0x1B, 0x61, 0x7F, + 0x60, 0xF3, 0x05, 0x01, 0x61, 0x77, 0xA1, 0x7F, 0x60, 0xF3, 0x05, 0x01, + 0xA1, 0x77, 0xE0, 0x7F, + 0x20, 0xF0, 0x08, 0x00, 0xE0, 0x77, 0x1C, 0xBD, 0x1F, 0xB5, 0x04, 0x46, + 0x03, 0x99, 0x02, 0xA8, + 0x01, 0xF0, 0x3F, 0x01, 0x03, 0x91, 0x08, 0x21, 0x00, 0xF0, 0x0D, 0xFA, + 0xDD, 0xE9, 0x02, 0x12, + 0xA1, 0x64, 0x84, 0xF8, 0x4C, 0x20, 0x14, 0xF8, 0x70, 0x1F, 0x60, 0xF3, + 0x05, 0x01, 0x04, 0xF8, + 0x1E, 0x19, 0xE1, 0x7F, 0x60, 0xF3, 0x05, 0x01, 0xE1, 0x77, 0x1F, 0xBD, + 0x10, 0xB5, 0x30, 0xA3, + 0x89, 0xB0, 0x1C, 0xCB, 0x8D, 0xE8, 0x1C, 0x00, 0x30, 0xA4, 0x0D, 0xF1, + 0x0C, 0x0C, 0x1C, 0xCC, + 0x8C, 0xE8, 0x1C, 0x00, 0x30, 0xA4, 0x0D, 0xF1, 0x18, 0x0C, 0x1C, 0xCC, + 0x8C, 0xE8, 0x1C, 0x00, + 0x03, 0xAA, 0x53, 0x5C, 0x42, 0x7E, 0x63, 0xF3, 0x05, 0x02, 0x42, 0x76, + 0x1D, 0xF8, 0x01, 0x30, + 0x02, 0x7E, 0x63, 0xF3, 0x42, 0x02, 0x02, 0x76, 0x06, 0xAA, 0x52, 0x5C, + 0x81, 0x79, 0x62, 0xF3, + 0x83, 0x01, 0x81, 0x71, 0x09, 0xB0, 0x10, 0xBD, 0x1A, 0x49, 0x04, 0x20, + 0x08, 0x70, 0x1A, 0x49, + 0x24, 0x48, 0x08, 0x60, 0x24, 0x49, 0x01, 0x20, 0xC1, 0xF8, 0xC0, 0x00, + 0x23, 0x49, 0x4F, 0xF4, + 0xFA, 0x70, 0xFF, 0xF7, 0x39, 0xBD, 0x10, 0xB5, 0xB0, 0xF8, 0x56, 0x20, + 0x42, 0xF0, 0x01, 0x02, + 0xA0, 0xF8, 0x56, 0x20, 0x82, 0x79, 0x22, 0xF0, 0x01, 0x02, 0x42, 0xF0, + 0xE0, 0x02, 0x82, 0x71, + 0x0B, 0x4A, 0x11, 0x60, 0x0B, 0x4A, 0x04, 0x21, 0x11, 0x70, 0x0B, 0x4A, + 0x15, 0x49, 0x11, 0x60, + 0x01, 0x46, 0xA4, 0x22, 0x16, 0x48, 0x16, 0xF0, 0x58, 0xF9, 0x13, 0x49, + 0x01, 0x20, 0xC1, 0xF8, + 0xC0, 0x00, 0xBD, 0xE8, 0x10, 0x40, 0x11, 0x49, 0x4F, 0xF4, 0xFA, 0x70, + 0xFF, 0xF7, 0x14, 0xBD, + 0x24, 0x04, 0x10, 0x00, 0x14, 0x04, 0x10, 0x00, 0x18, 0x04, 0x10, 0x00, + 0xFF, 0xFF, 0x03, 0x1C, + 0x00, 0x00, 0x02, 0x02, 0x01, 0x01, 0x03, 0x03, 0x03, 0x03, 0x00, 0x00, + 0x02, 0x02, 0x02, 0x02, + 0x02, 0x02, 0x02, 0x02, 0x01, 0x01, 0x00, 0x00, 0x02, 0x03, 0x02, 0x03, + 0x02, 0x03, 0x02, 0x03, + 0x02, 0x03, 0x00, 0x00, 0x29, 0x0D, 0x00, 0x00, 0x00, 0x00, 0x60, 0x22, + 0x21, 0x0D, 0x00, 0x00, + 0x00, 0x00, 0x03, 0x20, 0x35, 0x49, 0x01, 0x20, 0x08, 0x60, 0x17, 0x22, + 0x41, 0x07, 0x01, 0xF8, + 0x27, 0x2F, 0x0B, 0x22, 0x81, 0xF8, 0x41, 0x20, 0x30, 0x49, 0x18, 0x39, + 0x08, 0x60, 0x4F, 0xF0, + 0x08, 0x51, 0xC1, 0xF8, 0xC4, 0x03, 0x2D, 0x4A, 0x00, 0x21, 0xB0, 0x32, + 0x11, 0x60, 0x2C, 0x49, + 0x08, 0x60, 0x09, 0x1D, 0x08, 0x60, 0x29, 0x49, 0x94, 0x39, 0x08, 0x60, + 0x70, 0x47, 0x4F, 0xF0, + 0x00, 0x50, 0x00, 0x88, 0x70, 0x47, 0x4F, 0xF0, 0x00, 0x50, 0x80, 0x78, + 0x70, 0x47, 0x4F, 0xF0, + 0x00, 0x51, 0x88, 0x80, 0x70, 0x47, 0x21, 0x49, 0x01, 0x20, 0x30, 0x39, + 0x08, 0x60, 0x70, 0x47, + 0x4F, 0xF0, 0x00, 0x50, 0x10, 0xF8, 0x22, 0x1F, 0x21, 0xF0, 0x03, 0x01, + 0x01, 0x70, 0x70, 0x47, + 0x4F, 0xF0, 0x00, 0x53, 0x03, 0xF8, 0x1F, 0x0F, 0x59, 0x70, 0x98, 0x78, + 0x62, 0xF3, 0x03, 0x00, + 0x98, 0x70, 0x70, 0x47, 0x17, 0x48, 0x00, 0x68, 0x70, 0x47, 0x16, 0x49, + 0x08, 0x60, 0x70, 0x47, + 0x10, 0xB5, 0x4F, 0xF0, 0x00, 0x54, 0xE2, 0x7E, 0x22, 0xF0, 0xAF, 0x03, + 0x20, 0x22, 0x02, 0xEA, + 0x40, 0x12, 0x1A, 0x43, 0x04, 0x23, 0x03, 0xEA, 0x80, 0x00, 0x02, 0x43, + 0x01, 0xF0, 0x03, 0x00, + 0x02, 0x43, 0xE2, 0x76, 0x10, 0xBD, 0x4F, 0xF0, 0x00, 0x50, 0x90, 0xF8, + 0x22, 0x00, 0x10, 0xF0, + 0x03, 0x00, 0x05, 0xD0, 0x01, 0x28, 0x05, 0xD0, 0x02, 0x28, 0x05, 0xD0, + 0x06, 0x48, 0x70, 0x47, + 0x06, 0x48, 0x70, 0x47, 0x06, 0x48, 0x70, 0x47, 0x06, 0x48, 0x70, 0x47, + 0xCC, 0x04, 0x00, 0x22, + 0x80, 0x1E, 0x00, 0x22, 0x28, 0x04, 0x10, 0x00, 0x00, 0x12, 0x7A, 0x00, + 0x00, 0x90, 0xD0, 0x03, + 0x00, 0x48, 0xE8, 0x01, 0x00, 0x24, 0xF4, 0x00, 0x30, 0xB5, 0x6C, 0x4C, + 0x01, 0x25, 0x25, 0x60, + 0xE5, 0x06, 0x03, 0xF0, 0x1F, 0x03, 0x85, 0xF8, 0x6B, 0x30, 0x00, 0x23, + 0x05, 0xE0, 0x00, 0xBF, + 0x51, 0xF8, 0x23, 0x50, 0x40, 0xF8, 0x23, 0x50, 0x5B, 0x1C, 0x93, 0x42, + 0xF8, 0xDB, 0x00, 0x20, + 0x20, 0x60, 0x30, 0xBD, 0xF0, 0xB5, 0x06, 0x46, 0x00, 0x20, 0x04, 0x46, + 0xDF, 0xF8, 0x80, 0xC1, + 0x14, 0xE0, 0x56, 0xF8, 0x24, 0x70, 0x03, 0x23, 0xDD, 0x00, 0x47, 0xFA, + 0x05, 0xF2, 0x80, 0xEA, + 0x02, 0x60, 0x08, 0x25, 0x00, 0x28, 0x02, 0xDA, 0x8C, 0xEA, 0x40, 0x00, + 0x00, 0xE0, 0x40, 0x00, + 0x6D, 0x1E, 0x00, 0x2D, 0xF6, 0xDC, 0x5B, 0x1E, 0xEE, 0xD5, 0x64, 0x1C, + 0x8C, 0x42, 0xE8, 0xDB, + 0xF0, 0xBD, 0xF0, 0xB5, 0xB1, 0xB0, 0x07, 0x46, 0x6D, 0x46, 0x52, 0x4E, + 0x01, 0x24, 0xC0, 0x21, + 0x28, 0x46, 0x16, 0xF0, 0x13, 0xF9, 0x00, 0x20, 0x56, 0xF8, 0x20, 0x10, + 0x45, 0xF8, 0x20, 0x10, + 0x40, 0x1C, 0x30, 0x28, 0xF8, 0xD3, 0x4C, 0x49, 0x00, 0x98, 0x88, 0x42, + 0x10, 0xD1, 0x02, 0x98, + 0x81, 0xB2, 0x05, 0xA8, 0x04, 0x46, 0xFF, 0xF7, 0xC5, 0xFF, 0x01, 0x99, + 0x81, 0x42, 0x06, 0xD1, + 0xAC, 0x22, 0x21, 0x46, 0x38, 0x46, 0x16, 0xF0, 0x9D, 0xF8, 0x00, 0x24, + 0x00, 0xE0, 0x03, 0x24, + 0x31, 0xB0, 0x20, 0x46, 0xF0, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x41, 0x4D, + 0x07, 0x46, 0x3F, 0x4E, + 0x01, 0x24, 0x4F, 0xF4, 0x58, 0x71, 0x28, 0x46, 0x16, 0xF0, 0xE8, 0xF8, + 0x5F, 0xF0, 0x00, 0x00, + 0x56, 0xF8, 0x20, 0x10, 0x45, 0xF8, 0x20, 0x10, 0x40, 0x1C, 0xD8, 0x28, + 0xF8, 0xD3, 0x38, 0x4D, + 0x38, 0x49, 0x28, 0x68, 0x88, 0x42, 0x12, 0xD1, 0x28, 0x89, 0x81, 0xB2, + 0x05, 0xF1, 0x14, 0x00, + 0xFF, 0xF7, 0x98, 0xFF, 0x69, 0x68, 0x81, 0x42, 0x08, 0xD1, 0x4F, 0xF4, + 0x52, 0x72, 0x05, 0xF1, + 0x18, 0x01, 0x38, 0x46, 0x16, 0xF0, 0x29, 0xF8, 0x00, 0x24, 0x00, 0xE0, + 0x03, 0x24, 0x20, 0x46, + 0xBD, 0xE8, 0xF0, 0x81, 0x70, 0xB5, 0x94, 0xB0, 0x04, 0x46, 0x6D, 0x46, + 0x2A, 0x4E, 0x50, 0x21, + 0x28, 0x46, 0x16, 0xF0, 0xBB, 0xF8, 0x00, 0x20, 0x56, 0xF8, 0x20, 0x10, + 0x45, 0xF8, 0x20, 0x10, + 0x40, 0x1C, 0x14, 0x28, 0xF8, 0xD3, 0x25, 0x49, 0x00, 0x98, 0x6F, 0xF0, + 0x02, 0x05, 0x88, 0x42, + 0x2E, 0xD1, 0xA8, 0x10, 0x20, 0x60, 0x60, 0x60, 0xA0, 0x60, 0xE0, 0x60, + 0x20, 0x61, 0x02, 0x98, + 0x81, 0xB2, 0x05, 0xA8, 0xFF, 0xF7, 0x66, 0xFF, 0x01, 0x99, 0x81, 0x42, + 0x20, 0xD1, 0xBD, 0xF8, + 0x38, 0x10, 0x45, 0xF2, 0xAA, 0x50, 0x81, 0x42, 0x0C, 0xD1, 0x9D, 0xF8, + 0x1D, 0x10, 0x21, 0x60, + 0x9D, 0xF8, 0x1C, 0x10, 0x01, 0xF0, 0x0F, 0x01, 0x61, 0x60, 0x9D, 0xF8, + 0x1E, 0x10, 0x01, 0xF0, + 0x0F, 0x01, 0xA1, 0x60, 0xBD, 0xF8, 0x3C, 0x10, 0x81, 0x42, 0x01, 0xD1, + 0x08, 0x99, 0xE1, 0x60, + 0xBD, 0xF8, 0x40, 0x10, 0x81, 0x42, 0x01, 0xD1, 0x09, 0x98, 0x20, 0x61, + 0x14, 0xB0, 0x70, 0xBD, + 0x25, 0x60, 0x65, 0x60, 0xA5, 0x60, 0xE5, 0x60, 0x25, 0x61, 0xF7, 0xE7, + 0xC4, 0x1B, 0x00, 0x22, + 0x1B, 0x00, 0x00, 0x80, 0x48, 0x1D, 0x04, 0x00, 0xB2, 0x57, 0x0E, 0x70, + 0xE8, 0x19, 0x04, 0x00, + 0x54, 0x0B, 0x10, 0x00, 0xA1, 0x46, 0x0D, 0x60, 0xAC, 0x1E, 0x04, 0x00, + 0x5C, 0x00, 0x0D, 0x60, + 0xF0, 0xB5, 0x07, 0x46, 0x00, 0x20, 0x03, 0x46, 0x2F, 0x4E, 0x11, 0xE0, + 0x57, 0xF8, 0x23, 0x50, + 0x03, 0x22, 0x00, 0xBF, 0x4F, 0xEA, 0xC2, 0x0C, 0x45, 0xFA, 0x0C, 0xF4, + 0x84, 0xEA, 0x20, 0x64, + 0xE4, 0xB2, 0x52, 0x1E, 0x56, 0xF8, 0x24, 0x40, 0x84, 0xEA, 0x00, 0x20, + 0xF2, 0xD5, 0x5B, 0x1C, + 0x8B, 0x42, 0xEB, 0xDB, 0xF0, 0xBD, 0x30, 0xB5, 0x02, 0x46, 0x23, 0x4B, + 0x00, 0x20, 0x10, 0x3B, + 0x08, 0xE0, 0x54, 0x5C, 0x04, 0xF0, 0x0F, 0x05, 0x03, 0xEB, 0x14, 0x14, + 0x5D, 0x5D, 0x24, 0x78, + 0x28, 0x44, 0x20, 0x44, 0x49, 0x1E, 0xF4, 0xD2, 0x30, 0xBD, 0x10, 0xB5, + 0x84, 0x68, 0x03, 0x68, + 0xE4, 0x43, 0xA3, 0x42, 0x0A, 0xD1, 0xC4, 0x68, 0x43, 0x68, 0xE4, 0x43, + 0xA3, 0x42, 0x05, 0xD1, + 0x5B, 0x1C, 0x0B, 0x60, 0x00, 0x68, 0x10, 0x60, 0x01, 0x20, 0x10, 0xBD, + 0x00, 0x20, 0x10, 0xBD, + 0x3C, 0xB5, 0x04, 0x46, 0x00, 0x25, 0x01, 0xAA, 0x69, 0x46, 0xFF, 0xF7, + 0xE6, 0xFF, 0x01, 0x28, + 0x09, 0xD1, 0x00, 0x99, 0x04, 0xF1, 0x10, 0x00, 0x09, 0x1F, 0xFF, 0xF7, + 0xB1, 0xFF, 0x01, 0x99, + 0x88, 0x42, 0x00, 0xD1, 0x01, 0x25, 0x28, 0x46, 0x3C, 0xBD, 0x30, 0xB5, + 0x0D, 0x46, 0x04, 0x46, + 0x09, 0x1F, 0x10, 0x30, 0xFF, 0xF7, 0xA4, 0xFF, 0x6D, 0x1E, 0x65, 0x60, + 0xE9, 0x43, 0xE1, 0x60, + 0x20, 0x60, 0xC0, 0x43, 0xA0, 0x60, 0x30, 0xBD, 0xFC, 0x74, 0x01, 0x00, + 0x4F, 0xF0, 0x00, 0x50, + 0x00, 0x21, 0x80, 0xF8, 0x3D, 0x10, 0x80, 0xF8, 0x3E, 0x10, 0x80, 0xF8, + 0x3F, 0x10, 0x3F, 0x22, + 0x80, 0xF8, 0x32, 0x20, 0x00, 0xF8, 0x30, 0x1F, 0x02, 0x71, 0x41, 0x71, + 0x42, 0x70, 0x01, 0x72, + 0x41, 0x72, 0x81, 0x72, 0xC1, 0x72, 0xC1, 0x71, 0x70, 0x47, 0x28, 0x4A, + 0x10, 0x60, 0x27, 0x48, + 0x0C, 0x30, 0x01, 0x60, 0x70, 0x47, 0x30, 0xB5, 0x01, 0x24, 0x84, 0x40, + 0x4F, 0xF0, 0x00, 0x50, + 0x00, 0x29, 0x03, 0x9D, 0x90, 0xF8, 0x32, 0x10, 0xE4, 0xB2, 0x01, 0xD0, + 0x21, 0x43, 0x00, 0xE0, + 0xA1, 0x43, 0x80, 0xF8, 0x32, 0x10, 0x90, 0xF8, 0x30, 0x10, 0x0A, 0xB1, + 0x21, 0x43, 0x00, 0xE0, + 0xA1, 0x43, 0x80, 0xF8, 0x30, 0x10, 0x90, 0xF8, 0x34, 0x10, 0x0B, 0xB1, + 0x21, 0x43, 0x00, 0xE0, + 0xA1, 0x43, 0x80, 0xF8, 0x34, 0x10, 0x10, 0xF8, 0x35, 0x1F, 0x0D, 0xB1, + 0x21, 0x43, 0x00, 0xE0, + 0xA1, 0x43, 0x01, 0x70, 0x30, 0xBD, 0x4F, 0xF0, 0x00, 0x52, 0x06, 0x28, + 0x17, 0xD2, 0xDF, 0xE8, + 0x00, 0xF0, 0x03, 0x06, 0x09, 0x0F, 0x17, 0x1A, 0x12, 0xF8, 0x3D, 0x0F, + 0x04, 0xE0, 0x12, 0xF8, + 0x3D, 0x0F, 0x07, 0xE0, 0x12, 0xF8, 0x3E, 0x0F, 0x20, 0xF0, 0x0F, 0x00, + 0x08, 0x43, 0x05, 0xE0, + 0x12, 0xF8, 0x3E, 0x0F, 0x20, 0xF0, 0xF0, 0x00, 0x40, 0xEA, 0x01, 0x10, + 0x10, 0x70, 0x70, 0x47, + 0x12, 0xF8, 0x3F, 0x0F, 0xF0, 0xE7, 0x12, 0xF8, 0x3F, 0x0F, 0xF3, 0xE7, + 0x38, 0x05, 0x00, 0x22, + 0xF0, 0xB5, 0x63, 0x4C, 0xD0, 0xE9, 0x00, 0x25, 0x01, 0x21, 0xE3, 0x1D, + 0x06, 0x7A, 0xFF, 0x27, + 0x48, 0x07, 0x80, 0xF8, 0xE5, 0x70, 0x80, 0xF8, 0xE4, 0x70, 0x00, 0x27, + 0xC0, 0xF8, 0xC0, 0x70, + 0xC0, 0xF8, 0xE8, 0x70, 0x80, 0xF8, 0xE1, 0x70, 0x80, 0xF8, 0xE3, 0x70, + 0x8E, 0x46, 0x58, 0xE0, + 0x17, 0x78, 0x04, 0xF8, 0x01, 0x7B, 0x2F, 0x88, 0x23, 0xF8, 0x02, 0x7B, + 0xD7, 0x78, 0x01, 0x2F, + 0x02, 0xD0, 0x02, 0x2F, 0x09, 0xD0, 0x10, 0xE0, 0x90, 0xF8, 0xE4, 0x70, + 0x0E, 0xFA, 0x01, 0xFC, + 0x27, 0xEA, 0x0C, 0x07, 0x80, 0xF8, 0xE4, 0x70, 0x07, 0xE0, 0x90, 0xF8, + 0xE5, 0x70, 0x0E, 0xFA, + 0x01, 0xFC, 0x27, 0xEA, 0x0C, 0x07, 0x80, 0xF8, 0xE5, 0x70, 0x4F, 0x1E, + 0x07, 0xEB, 0x47, 0x0C, + 0x27, 0xF0, 0x01, 0x07, 0xBC, 0x44, 0x57, 0x78, 0x07, 0xF0, 0x07, 0x07, + 0x07, 0xFA, 0x0C, 0xF7, + 0xD0, 0xF8, 0xC0, 0xC0, 0x47, 0xEA, 0x0C, 0x07, 0xC0, 0xF8, 0xC0, 0x70, + 0x97, 0x78, 0x4F, 0xEA, + 0x81, 0x0C, 0x07, 0xF0, 0x0F, 0x07, 0xAC, 0xF1, 0x04, 0x0C, 0x07, 0xFA, + 0x0C, 0xF7, 0xD0, 0xF8, + 0xE8, 0xC0, 0x47, 0xEA, 0x0C, 0x07, 0xC0, 0xF8, 0xE8, 0x70, 0x17, 0x79, + 0xFF, 0x07, 0x07, 0xD0, + 0x90, 0xF8, 0xE1, 0xC0, 0x0E, 0xFA, 0x01, 0xF7, 0x4C, 0xEA, 0x07, 0x0C, + 0x80, 0xF8, 0xE1, 0xC0, + 0x17, 0x79, 0xFF, 0x06, 0x07, 0xD5, 0x90, 0xF8, 0xE3, 0x70, 0x0E, 0xFA, + 0x01, 0xFC, 0x47, 0xEA, + 0x0C, 0x07, 0x80, 0xF8, 0xE3, 0x70, 0x49, 0x1C, 0x08, 0x29, 0x04, 0xD2, + 0x52, 0x1D, 0xAD, 0x1C, + 0x76, 0x1E, 0x00, 0x2E, 0xA4, 0xD1, 0xD0, 0xF8, 0xE8, 0x10, 0x41, 0x64, + 0xF0, 0xBD, 0xF0, 0xB5, + 0x27, 0x4D, 0x28, 0x49, 0x01, 0x26, 0xEC, 0x1D, 0xC3, 0x79, 0x00, 0x22, + 0x07, 0x68, 0x4A, 0x60, + 0x09, 0x04, 0x4F, 0xF0, 0xFF, 0x0E, 0x81, 0xF8, 0xE5, 0xE0, 0x81, 0xF8, + 0xE4, 0x60, 0xC1, 0xF8, + 0xC0, 0x20, 0x81, 0xF8, 0xE1, 0x20, 0x81, 0xF8, 0xE3, 0x20, 0x18, 0xE0, + 0x97, 0xF8, 0x00, 0xC0, + 0x05, 0xF8, 0x01, 0xCB, 0xB0, 0xF8, 0x04, 0xC0, 0x24, 0xF8, 0x02, 0xCB, + 0x90, 0xF8, 0x06, 0xC0, + 0x4F, 0xEA, 0x86, 0x0E, 0x0C, 0xF0, 0x0F, 0x0C, 0xAE, 0xF1, 0x04, 0x0E, + 0x0C, 0xFA, 0x0E, 0xFC, + 0x76, 0x1C, 0x4C, 0xEA, 0x02, 0x02, 0x08, 0x2E, 0x03, 0xD2, 0x5B, 0x1E, + 0x7F, 0x1C, 0x00, 0x2B, + 0xE4, 0xD1, 0xC1, 0xF8, 0xE8, 0x20, 0x4A, 0x64, 0xF0, 0xBD, 0x0D, 0x4A, + 0xD2, 0x1D, 0x22, 0xF8, + 0x10, 0x10, 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, 0x0B, 0x48, 0x00, 0x68, + 0x38, 0xB1, 0xA0, 0x68, + 0xFF, 0xF7, 0x46, 0xFF, 0x20, 0x68, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, + 0x0F, 0xB8, 0xE0, 0x68, + 0xFF, 0xF7, 0x3E, 0xFF, 0x60, 0x68, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, + 0xAB, 0xB8, 0x00, 0x00, + 0xAB, 0x00, 0x00, 0x20, 0x00, 0x20, 0x00, 0x22, 0xBC, 0x05, 0x00, 0x22, + 0x10, 0xB5, 0x4F, 0x49, + 0x02, 0x68, 0x00, 0x24, 0x8A, 0x60, 0x82, 0x88, 0x4A, 0x80, 0x03, 0x89, + 0x8B, 0x80, 0x0C, 0x70, + 0x4F, 0xF0, 0x00, 0x51, 0xA1, 0xF8, 0x1A, 0x31, 0xA1, 0xF8, 0x1E, 0x21, + 0xC0, 0x88, 0xA1, 0xF8, + 0x20, 0x01, 0x47, 0x48, 0x01, 0x21, 0xC0, 0xF8, 0xD8, 0x11, 0xC0, 0xF8, + 0xDC, 0x11, 0xC0, 0xF8, + 0xC4, 0x11, 0xC0, 0xF8, 0xCC, 0x11, 0xC0, 0xF8, 0xD4, 0x11, 0xC0, 0xF8, + 0x80, 0x11, 0x72, 0xB6, + 0xD0, 0xF8, 0x08, 0x22, 0x00, 0x2A, 0xFB, 0xD1, 0x41, 0x60, 0x62, 0xB6, + 0x10, 0xBD, 0x2D, 0xE9, + 0xF0, 0x41, 0x3B, 0x4C, 0xD4, 0xF8, 0x5C, 0x01, 0x38, 0x4E, 0x25, 0x04, + 0x01, 0x27, 0xB2, 0x68, + 0x50, 0xB3, 0xB5, 0xF8, 0x1C, 0x81, 0x5F, 0xEA, 0x08, 0x00, 0x0F, 0xD0, + 0xD4, 0xF8, 0x54, 0x01, + 0x10, 0xB9, 0xD4, 0xF8, 0x00, 0x01, 0x48, 0xB1, 0x41, 0x46, 0x01, 0x20, + 0x90, 0x47, 0xC4, 0xF8, + 0xD8, 0x72, 0xD4, 0xF8, 0x54, 0x01, 0x08, 0xB1, 0xC4, 0xF8, 0xD4, 0x72, + 0xB2, 0x68, 0x41, 0x46, + 0x02, 0x20, 0x90, 0x47, 0x01, 0x78, 0x02, 0x29, 0x02, 0xD0, 0x03, 0x29, + 0x02, 0xD0, 0x08, 0xE0, + 0x41, 0x88, 0x00, 0xE0, 0x71, 0x88, 0xA5, 0xF8, 0x1E, 0x11, 0x80, 0x88, + 0xA5, 0xF8, 0x1A, 0x01, + 0x37, 0x70, 0xC4, 0xF8, 0xDC, 0x72, 0x38, 0xE0, 0xD4, 0xF8, 0x44, 0x01, + 0x80, 0xB1, 0xB5, 0xF8, + 0x1C, 0x11, 0x03, 0x20, 0x90, 0x47, 0x30, 0x78, 0x38, 0xB1, 0x70, 0x88, + 0xA5, 0xF8, 0x1E, 0x01, + 0xB0, 0x88, 0xA5, 0xF8, 0x1A, 0x01, 0x00, 0x20, 0x30, 0x70, 0xC4, 0xF8, + 0xC4, 0x72, 0x24, 0xE0, + 0xD4, 0xF8, 0x58, 0x01, 0x30, 0xB1, 0xB5, 0xF8, 0x1C, 0x11, 0x01, 0x20, + 0x90, 0x47, 0xC4, 0xF8, + 0xD8, 0x72, 0x1A, 0xE0, 0xD4, 0xF8, 0x4C, 0x01, 0x28, 0xB9, 0xD4, 0xF8, + 0x54, 0x01, 0x10, 0xB9, + 0xD4, 0xF8, 0x00, 0x01, 0x88, 0xB1, 0xB5, 0xF8, 0x1C, 0x11, 0x19, 0xB1, + 0x01, 0x20, 0x90, 0x47, + 0xC4, 0xF8, 0xD8, 0x72, 0xD4, 0xF8, 0x4C, 0x01, 0x10, 0xB1, 0xC4, 0xF8, + 0xCC, 0x72, 0x04, 0xE0, + 0xD4, 0xF8, 0x54, 0x01, 0x08, 0xB1, 0xC4, 0xF8, 0xD4, 0x72, 0xD4, 0xF8, + 0x00, 0x01, 0x00, 0x28, + 0x01, 0xD0, 0xC4, 0xF8, 0x80, 0x72, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x00, + 0x2C, 0x04, 0x10, 0x00, + 0x00, 0x20, 0x00, 0x22, 0xC1, 0x7D, 0x01, 0x29, 0x05, 0xD1, 0x49, 0x07, + 0x11, 0xF8, 0x2D, 0x2F, + 0x42, 0xF0, 0x02, 0x02, 0x0A, 0x70, 0x04, 0x49, 0x02, 0x68, 0x4A, 0x60, + 0x42, 0x68, 0x8A, 0x60, + 0x80, 0x7D, 0x08, 0x70, 0x70, 0x47, 0x00, 0x00, 0x38, 0x04, 0x10, 0x00, + 0xE9, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x09, 0x1D, 0x08, 0x60, 0x09, 0x1D, 0x08, 0x60, 0x09, 0x1D, + 0x08, 0x60, 0x09, 0x1D, + 0x08, 0x60, 0x09, 0x1D, 0x08, 0x60, 0x09, 0x1D, 0x08, 0x60, 0x09, 0x1D, + 0x08, 0x60, 0xE2, 0x49, + 0x01, 0x22, 0x0A, 0x60, 0xE0, 0x49, 0x14, 0x31, 0x08, 0x60, 0x51, 0x07, + 0x01, 0xF8, 0x50, 0x0F, + 0xF0, 0x23, 0x4B, 0x70, 0x0F, 0x23, 0x01, 0xF8, 0x05, 0x3C, 0x10, 0x23, + 0x4B, 0x80, 0x8A, 0x80, + 0xDA, 0x49, 0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xC8, 0x60, 0x08, 0x61, + 0x48, 0x61, 0x88, 0x61, + 0xC8, 0x61, 0x08, 0x62, 0x70, 0x47, 0x70, 0x47, 0xD4, 0x4A, 0x11, 0x60, + 0xD1, 0x49, 0x00, 0x22, + 0x0A, 0x60, 0x00, 0xEB, 0xC0, 0x02, 0x02, 0xEB, 0x00, 0x10, 0x4F, 0xF6, + 0xFF, 0x72, 0x02, 0xEA, + 0x80, 0x00, 0x4F, 0xF0, 0x00, 0x52, 0xA2, 0xF8, 0x58, 0x00, 0x01, 0x20, + 0x08, 0x60, 0x70, 0x47, + 0x4F, 0xF0, 0x00, 0x50, 0x90, 0xF8, 0x22, 0x00, 0xC0, 0xF3, 0x81, 0x00, + 0x28, 0xB1, 0x01, 0x28, + 0x05, 0xD0, 0x02, 0x28, 0x05, 0xD0, 0xC6, 0x48, 0x70, 0x47, 0xC6, 0x48, + 0x70, 0x47, 0xC6, 0x48, + 0x70, 0x47, 0xC6, 0x48, 0x70, 0x47, 0x70, 0xB5, 0x4F, 0xF0, 0x00, 0x54, + 0x72, 0xB6, 0x65, 0x69, + 0x60, 0x69, 0x40, 0xF0, 0x04, 0x00, 0x60, 0x61, 0xBA, 0x49, 0x00, 0x20, + 0x08, 0x60, 0xB4, 0xF8, + 0x58, 0x10, 0x09, 0xB1, 0xA4, 0xF8, 0x58, 0x00, 0xFF, 0xF7, 0x35, 0xFC, + 0x01, 0x46, 0xFF, 0xF7, + 0xD7, 0xFF, 0xB1, 0xFB, 0xF0, 0xF0, 0xFE, 0xF7, 0xCD, 0xFD, 0x65, 0x61, + 0x02, 0x20, 0x00, 0xF0, + 0x56, 0xF9, 0x62, 0xB6, 0x70, 0xBD, 0xB1, 0x48, 0x10, 0xB5, 0x00, 0x21, + 0x04, 0x68, 0x01, 0x60, + 0xFF, 0xF7, 0xD9, 0xFF, 0x1C, 0xB1, 0xA4, 0x46, 0xBD, 0xE8, 0x10, 0x40, + 0x60, 0x47, 0x00, 0x20, + 0xFF, 0xF7, 0xA9, 0xFF, 0x10, 0xBD, 0xA9, 0x4A, 0x51, 0x60, 0xA6, 0x49, + 0x00, 0x22, 0x09, 0x1D, + 0x0A, 0x60, 0x00, 0xEB, 0xC0, 0x02, 0x02, 0xEB, 0x00, 0x10, 0x4F, 0xF6, + 0xFF, 0x72, 0x02, 0xEA, + 0x80, 0x00, 0xCA, 0x06, 0xA2, 0xF8, 0x5A, 0x00, 0x01, 0x20, 0x08, 0x60, + 0x70, 0x47, 0x70, 0xB5, + 0x4F, 0xF0, 0x00, 0x54, 0x72, 0xB6, 0x65, 0x69, 0x60, 0x69, 0x40, 0xF0, + 0x08, 0x00, 0x60, 0x61, + 0x98, 0x49, 0x00, 0x20, 0x09, 0x1D, 0x08, 0x60, 0xB4, 0xF8, 0x5A, 0x10, + 0x09, 0xB1, 0xA4, 0xF8, + 0x5A, 0x00, 0xFF, 0xF7, 0xF0, 0xFB, 0x01, 0x46, 0xFF, 0xF7, 0x92, 0xFF, + 0xB1, 0xFB, 0xF0, 0xF0, + 0xFE, 0xF7, 0x88, 0xFD, 0x65, 0x61, 0x03, 0x20, 0x00, 0xF0, 0x11, 0xF9, + 0x62, 0xB6, 0x70, 0xBD, + 0x8E, 0x48, 0x10, 0xB5, 0x00, 0x21, 0x44, 0x68, 0x41, 0x60, 0xFF, 0xF7, + 0xD8, 0xFF, 0x1C, 0xB1, + 0xA4, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x60, 0x47, 0x01, 0x20, 0xFF, 0xF7, + 0x64, 0xFF, 0x10, 0xBD, + 0x70, 0xB5, 0x4F, 0xF0, 0x00, 0x54, 0x72, 0xB6, 0x65, 0x69, 0x60, 0x69, + 0x40, 0xF0, 0x10, 0x00, + 0x60, 0x61, 0x80, 0x49, 0x00, 0x20, 0x08, 0x31, 0x08, 0x60, 0xB4, 0xF8, + 0x5C, 0x10, 0x09, 0xB1, + 0xA4, 0xF8, 0x5C, 0x00, 0xFF, 0xF7, 0xBF, 0xFB, 0x01, 0x46, 0xFF, 0xF7, + 0x61, 0xFF, 0xB1, 0xFB, + 0xF0, 0xF0, 0xFE, 0xF7, 0x57, 0xFD, 0x65, 0x61, 0x04, 0x20, 0x00, 0xF0, + 0xE0, 0xF8, 0x62, 0xB6, + 0x70, 0xBD, 0x76, 0x48, 0x10, 0xB5, 0x00, 0x21, 0x84, 0x68, 0x81, 0x60, + 0xFF, 0xF7, 0xD8, 0xFF, + 0x1C, 0xB1, 0xA4, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x60, 0x47, 0x02, 0x20, + 0xFF, 0xF7, 0x33, 0xFF, + 0x10, 0xBD, 0x70, 0xB5, 0x4F, 0xF0, 0x00, 0x54, 0x72, 0xB6, 0x65, 0x69, + 0x60, 0x69, 0x40, 0xF0, + 0x20, 0x00, 0x60, 0x61, 0x67, 0x49, 0x00, 0x20, 0x0C, 0x31, 0x08, 0x60, + 0xB4, 0xF8, 0x5E, 0x10, + 0x09, 0xB1, 0xA4, 0xF8, 0x5E, 0x00, 0xFF, 0xF7, 0x8E, 0xFB, 0x01, 0x46, + 0xFF, 0xF7, 0x30, 0xFF, + 0xB1, 0xFB, 0xF0, 0xF0, 0xFE, 0xF7, 0x26, 0xFD, 0x65, 0x61, 0x05, 0x20, + 0x00, 0xF0, 0xAF, 0xF8, + 0x62, 0xB6, 0x70, 0xBD, 0x5D, 0x48, 0x10, 0xB5, 0x00, 0x21, 0xC4, 0x68, + 0xC1, 0x60, 0xFF, 0xF7, + 0xD8, 0xFF, 0x1C, 0xB1, 0xA4, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x60, 0x47, + 0x03, 0x20, 0xFF, 0xF7, + 0x02, 0xFF, 0x10, 0xBD, 0x4F, 0xF0, 0x00, 0x50, 0xB0, 0xF8, 0x60, 0x00, + 0x70, 0x47, 0x53, 0x49, + 0x10, 0xB5, 0x00, 0x22, 0x08, 0x69, 0x0A, 0x61, 0x4E, 0x49, 0x10, 0x31, + 0x0A, 0x60, 0x10, 0xB1, + 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x47, 0x04, 0x20, 0xFF, 0xF7, 0xED, 0xFE, + 0x10, 0xBD, 0x4B, 0x4A, + 0x00, 0x23, 0x51, 0x61, 0x47, 0x49, 0x14, 0x31, 0x0B, 0x60, 0x12, 0x6A, + 0x50, 0x43, 0x4F, 0xF0, + 0x00, 0x52, 0x80, 0x09, 0xA2, 0xF8, 0x62, 0x00, 0x01, 0x20, 0x08, 0x60, + 0x70, 0x47, 0x41, 0x49, + 0x00, 0x20, 0x14, 0x31, 0x08, 0x60, 0x70, 0x47, 0x40, 0x49, 0x10, 0xB5, + 0x00, 0x22, 0x48, 0x69, + 0x4A, 0x61, 0x3C, 0x49, 0x14, 0x31, 0x0A, 0x60, 0x10, 0xB1, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x47, + 0x05, 0x20, 0xFF, 0xF7, 0xC8, 0xFE, 0x10, 0xBD, 0x38, 0x49, 0x10, 0xB5, + 0x00, 0x22, 0x88, 0x69, + 0x8A, 0x61, 0x34, 0x49, 0x18, 0x31, 0x0A, 0x60, 0x10, 0xB1, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x47, + 0x06, 0x20, 0xFF, 0xF7, 0xB8, 0xFE, 0x10, 0xBD, 0x10, 0xB5, 0xFF, 0xF7, + 0x0B, 0xFB, 0x4F, 0xF0, + 0x00, 0x51, 0x91, 0xF8, 0x22, 0x20, 0x42, 0xF2, 0x10, 0x73, 0xB0, 0xFB, + 0xF3, 0xF0, 0xC2, 0xF3, + 0x81, 0x02, 0x52, 0x1C, 0xD0, 0x40, 0xB1, 0xF8, 0x54, 0x20, 0xC9, 0x6C, + 0x51, 0x43, 0x89, 0x09, + 0xB0, 0xFB, 0xF1, 0xF0, 0x10, 0xBD, 0x25, 0x49, 0xC8, 0x61, 0x22, 0x49, + 0x01, 0x20, 0xB8, 0x31, + 0x08, 0x60, 0x09, 0x1D, 0x08, 0x60, 0x70, 0x47, 0x20, 0x48, 0x10, 0xB5, + 0x00, 0x22, 0xC1, 0x69, + 0xC2, 0x61, 0x51, 0xB1, 0x1B, 0x48, 0xB8, 0x30, 0x02, 0x60, 0x4F, 0xF0, + 0x00, 0x50, 0xC0, 0x6C, + 0xBD, 0xE8, 0x10, 0x40, 0x20, 0xF0, 0x7F, 0x40, 0x08, 0x47, 0xFF, 0x20, + 0xFF, 0xF7, 0x83, 0xFE, + 0x10, 0xBD, 0x10, 0xB5, 0x04, 0x46, 0xFF, 0xF7, 0xD5, 0xFA, 0x4F, 0xF0, + 0x00, 0x51, 0x91, 0xF8, + 0x22, 0x10, 0x42, 0xF2, 0x10, 0x72, 0xB0, 0xFB, 0xF2, 0xF0, 0xC1, 0xF3, + 0x81, 0x01, 0x49, 0x1C, + 0xC8, 0x40, 0x00, 0x03, 0xB0, 0xFB, 0xF4, 0xF0, 0x0C, 0x49, 0x08, 0x62, + 0x10, 0xBD, 0x4F, 0xF0, + 0x00, 0x50, 0x90, 0xF8, 0x4A, 0x00, 0x00, 0x07, 0x00, 0xD0, 0x01, 0x20, + 0x70, 0x47, 0x00, 0xF0, + 0x1F, 0x02, 0x01, 0x21, 0x91, 0x40, 0x40, 0x09, 0x80, 0x00, 0x00, 0xF1, + 0xE0, 0x20, 0xC0, 0xF8, + 0x80, 0x12, 0x70, 0x47, 0x40, 0x09, 0x00, 0x22, 0xC0, 0x04, 0x00, 0x22, + 0x44, 0x04, 0x10, 0x00, + 0x00, 0x09, 0x3D, 0x00, 0x00, 0x48, 0xE8, 0x01, 0x00, 0x24, 0xF4, 0x00, + 0x00, 0x12, 0x7A, 0x00, + 0x10, 0xB5, 0x01, 0x46, 0x34, 0x22, 0xF6, 0x48, 0x15, 0xF0, 0xCC, 0xFB, + 0x01, 0x21, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x20, 0xFE, 0xF7, 0x8D, 0xBD, 0x38, 0xB5, 0x04, 0x46, + 0xF1, 0x48, 0xF0, 0x4D, + 0x20, 0x60, 0x20, 0x46, 0x15, 0xF0, 0x03, 0xF8, 0x00, 0x22, 0x6B, 0x46, + 0x01, 0x21, 0x10, 0x46, + 0xFE, 0xF7, 0xC8, 0xFD, 0x01, 0x21, 0x00, 0x20, 0xFE, 0xF7, 0xA7, 0xFD, + 0x28, 0x78, 0x00, 0x28, + 0x02, 0xD0, 0x10, 0xF0, 0x8A, 0xFD, 0xEC, 0xE7, 0x38, 0xBD, 0xE7, 0x48, + 0x02, 0x68, 0x92, 0xF8, + 0xB0, 0x00, 0xC1, 0x07, 0x0E, 0xD0, 0xE2, 0x49, 0x01, 0x23, 0x34, 0x31, + 0x4B, 0x73, 0xC0, 0xF3, + 0xC1, 0x03, 0x02, 0x2B, 0x01, 0xD1, 0x00, 0x23, 0x4B, 0x73, 0x80, 0x07, + 0x02, 0xD5, 0x92, 0xF8, + 0xBB, 0x00, 0x08, 0x73, 0x70, 0x47, 0xDC, 0x48, 0x10, 0xB5, 0x03, 0x68, + 0x93, 0xF8, 0xB0, 0x20, + 0xD0, 0x07, 0x16, 0xD0, 0x90, 0x07, 0x14, 0xD5, 0xD8, 0x48, 0x40, 0x78, + 0x00, 0x28, 0x10, 0xD1, + 0xD3, 0x48, 0x34, 0x30, 0x00, 0x21, 0x04, 0x7B, 0x0C, 0xB1, 0x41, 0x73, + 0x08, 0xE0, 0x01, 0x24, + 0xC2, 0xF3, 0xC1, 0x02, 0x44, 0x73, 0x02, 0x2A, 0x00, 0xD1, 0x41, 0x73, + 0x93, 0xF8, 0xBB, 0x10, + 0x01, 0x73, 0x10, 0xBD, 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, 0x2C, 0x83, + 0x82, 0x46, 0x01, 0x27, + 0xD8, 0xF8, 0x00, 0x00, 0xCA, 0x4D, 0x90, 0xF8, 0x31, 0x40, 0x10, 0xF8, + 0x30, 0x1F, 0x90, 0xF8, + 0x31, 0x00, 0x4C, 0x43, 0x00, 0xF0, 0x03, 0x00, 0x87, 0x40, 0xA1, 0x00, + 0x28, 0x46, 0x15, 0xF0, + 0xBD, 0xFB, 0xFF, 0xF7, 0xB2, 0xFF, 0x00, 0x26, 0xDF, 0xF8, 0xF4, 0x92, + 0x15, 0xE0, 0xBC, 0x48, + 0x34, 0x30, 0xFF, 0xF7, 0x91, 0xFF, 0x00, 0x20, 0xD9, 0xF8, 0x08, 0x10, + 0x08, 0xE0, 0x00, 0xBF, + 0x55, 0xF8, 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, 0x1A, 0x44, 0x45, 0xF8, + 0x20, 0x20, 0x40, 0x1C, + 0xA0, 0x42, 0xF5, 0xDB, 0xFF, 0xF7, 0xAF, 0xFF, 0x76, 0x1C, 0xBE, 0x42, + 0xE7, 0xDB, 0x40, 0x46, + 0x0A, 0xE0, 0x00, 0xBF, 0x02, 0x68, 0x55, 0xF8, 0x24, 0x10, 0x92, 0xF8, + 0x61, 0x20, 0x02, 0xF0, + 0x03, 0x02, 0x11, 0x41, 0x2A, 0xF8, 0x14, 0x10, 0x64, 0x1E, 0xF3, 0xD2, + 0xBD, 0xE8, 0xF0, 0x87, + 0x2D, 0xE9, 0xF0, 0x4F, 0xDF, 0xF8, 0xA0, 0xB2, 0x4F, 0xF0, 0x01, 0x09, + 0xA8, 0x4E, 0xDB, 0xF8, + 0x00, 0x00, 0x9F, 0xB0, 0x90, 0xF8, 0x61, 0x10, 0x90, 0xF8, 0x31, 0x40, + 0xC1, 0xF3, 0x81, 0x08, + 0x90, 0xF8, 0x30, 0x50, 0x09, 0xFA, 0x08, 0xFA, 0x60, 0x19, 0x81, 0x00, + 0x06, 0xEB, 0x84, 0x07, + 0x30, 0x46, 0x15, 0xF0, 0x73, 0xFB, 0x9A, 0x48, 0x34, 0x30, 0x14, 0xF0, + 0x33, 0xFF, 0x98, 0x48, + 0x34, 0x30, 0x80, 0xF8, 0x06, 0x90, 0xDB, 0xF8, 0x00, 0x10, 0x91, 0xF8, + 0x60, 0x20, 0x92, 0x07, + 0x01, 0xD5, 0x80, 0xF8, 0x04, 0x90, 0x91, 0xF8, 0x62, 0x10, 0x01, 0x73, + 0xFF, 0xF7, 0x55, 0xFF, + 0xDB, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x60, 0x00, 0xC0, 0x07, 0x05, 0xD0, + 0x8C, 0x48, 0x34, 0x30, + 0xFF, 0xF7, 0x32, 0xFF, 0xFF, 0xF7, 0x5F, 0xFF, 0x00, 0x20, 0x2E, 0xE0, + 0x88, 0x48, 0x34, 0x30, + 0xFF, 0xF7, 0x2A, 0xFF, 0xDF, 0xF8, 0x18, 0xB2, 0x62, 0x00, 0x13, 0xA8, + 0xDB, 0xF8, 0x18, 0x10, + 0x15, 0xF0, 0xA3, 0xFA, 0x6A, 0x00, 0x68, 0x46, 0xDB, 0xF8, 0x1C, 0x10, + 0x15, 0xF0, 0x9D, 0xFA, + 0x20, 0x46, 0x13, 0xA9, 0x07, 0xE0, 0x00, 0xBF, 0x56, 0xF8, 0x20, 0x20, + 0x31, 0xF9, 0x10, 0x30, + 0x1A, 0x44, 0x46, 0xF8, 0x20, 0x20, 0x40, 0x1E, 0xF6, 0xD2, 0x28, 0x46, + 0x69, 0x46, 0x06, 0xE0, + 0x57, 0xF8, 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, 0x1A, 0x44, 0x47, 0xF8, + 0x20, 0x20, 0x40, 0x1E, + 0xF6, 0xD2, 0xFF, 0xF7, 0x30, 0xFF, 0x09, 0xF1, 0x01, 0x00, 0x81, 0x46, + 0x50, 0x45, 0xCD, 0xDB, + 0x74, 0x49, 0x05, 0xE0, 0x56, 0xF8, 0x24, 0x00, 0x40, 0xFA, 0x08, 0xF0, + 0x21, 0xF8, 0x14, 0x00, + 0x64, 0x1E, 0xF7, 0xD2, 0x70, 0x49, 0x05, 0xE0, 0x57, 0xF8, 0x25, 0x00, + 0x40, 0xFA, 0x08, 0xF0, + 0x21, 0xF8, 0x15, 0x00, 0x6D, 0x1E, 0xF7, 0xD2, 0x1F, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, + 0xFF, 0x5F, 0xDF, 0xF8, 0x94, 0x81, 0x66, 0x4F, 0xD8, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0x31, 0x40, + 0x90, 0xF8, 0x30, 0x50, 0x07, 0xEB, 0x84, 0x0A, 0x60, 0x19, 0x81, 0x00, + 0x04, 0xFB, 0x05, 0xFB, + 0x0A, 0xEB, 0x85, 0x06, 0x38, 0x46, 0x15, 0xF0, 0xF1, 0xFA, 0x4F, 0xEA, + 0x8B, 0x01, 0x30, 0x46, + 0x15, 0xF0, 0xEC, 0xFA, 0x56, 0x48, 0x34, 0x30, 0x14, 0xF0, 0xAC, 0xFE, + 0x54, 0x48, 0x4F, 0xF0, + 0x01, 0x09, 0x34, 0x30, 0x80, 0xF8, 0x06, 0x90, 0x80, 0xF8, 0x04, 0x90, + 0xD8, 0xF8, 0x00, 0x10, + 0x91, 0xF8, 0x62, 0x10, 0x01, 0x73, 0xFF, 0xF7, 0xD0, 0xFE, 0xD8, 0xF8, + 0x00, 0x00, 0x90, 0xF8, + 0x60, 0x00, 0xC0, 0x07, 0x05, 0xD0, 0x4A, 0x48, 0x34, 0x30, 0xFF, 0xF7, + 0xAD, 0xFE, 0xFF, 0xF7, + 0xDA, 0xFE, 0xD8, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x61, 0x00, 0xC0, 0xF3, + 0x81, 0x01, 0x02, 0x91, + 0x00, 0xF0, 0x03, 0x01, 0x03, 0x91, 0x02, 0x99, 0x48, 0x46, 0x09, 0xFA, + 0x01, 0xF9, 0x03, 0x99, + 0x88, 0x40, 0x01, 0x90, 0x00, 0x20, 0x32, 0xE0, 0x3D, 0x48, 0x34, 0x30, + 0xFF, 0xF7, 0x94, 0xFE, + 0x3B, 0x48, 0xD0, 0xE9, 0x06, 0x32, 0x81, 0x68, 0x20, 0x46, 0x06, 0xE0, + 0x57, 0xF8, 0x20, 0xC0, + 0x33, 0xF9, 0x10, 0x80, 0xC4, 0x44, 0x47, 0xF8, 0x20, 0xC0, 0x40, 0x1E, + 0xF6, 0xD2, 0x28, 0x46, + 0x07, 0xE0, 0x00, 0xBF, 0x5A, 0xF8, 0x20, 0x30, 0x32, 0xF9, 0x10, 0xC0, + 0x9C, 0x44, 0x4A, 0xF8, + 0x20, 0xC0, 0x40, 0x1E, 0xF6, 0xD2, 0xDD, 0xE9, 0x00, 0x02, 0x90, 0x42, + 0x0B, 0xDA, 0x58, 0x46, + 0x07, 0xE0, 0x00, 0xBF, 0x56, 0xF8, 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, + 0x1A, 0x44, 0x46, 0xF8, + 0x20, 0x20, 0x40, 0x1E, 0xF6, 0xD2, 0xFF, 0xF7, 0x96, 0xFE, 0x00, 0x98, + 0x40, 0x1C, 0x00, 0x90, + 0x48, 0x45, 0xC9, 0xDB, 0x01, 0x98, 0x48, 0x45, 0x1F, 0xDD, 0x21, 0x48, + 0x00, 0x21, 0x34, 0x30, + 0x88, 0x46, 0x81, 0x71, 0x01, 0x99, 0xA1, 0xEB, 0x09, 0x09, 0x14, 0xE0, + 0x1C, 0x48, 0x34, 0x30, + 0xFF, 0xF7, 0x52, 0xFE, 0x1A, 0x48, 0x81, 0x68, 0x58, 0x46, 0x06, 0xE0, + 0x56, 0xF8, 0x20, 0x20, + 0x31, 0xF9, 0x10, 0x30, 0x1A, 0x44, 0x46, 0xF8, 0x20, 0x20, 0x40, 0x1E, + 0xF6, 0xD2, 0xFF, 0xF7, + 0x72, 0xFE, 0x08, 0xF1, 0x01, 0x08, 0xC1, 0x45, 0xE8, 0xDC, 0x16, 0x49, + 0x06, 0xE0, 0x00, 0xBF, + 0x57, 0xF8, 0x24, 0x00, 0x02, 0x9A, 0x10, 0x41, 0x21, 0xF8, 0x14, 0x00, + 0x64, 0x1E, 0xF7, 0xD2, + 0x11, 0x49, 0x05, 0xE0, 0x5A, 0xF8, 0x25, 0x00, 0x02, 0x9A, 0x10, 0x41, + 0x21, 0xF8, 0x15, 0x00, + 0x6D, 0x1E, 0xF7, 0xD2, 0x58, 0x46, 0x0D, 0x4A, 0x06, 0xE0, 0x00, 0xBF, + 0x56, 0xF8, 0x20, 0x10, + 0x03, 0x9B, 0x19, 0x41, 0x22, 0xF8, 0x10, 0x10, 0x40, 0x1E, 0xF7, 0xD2, + 0xBD, 0xE8, 0xFF, 0x9F, + 0xF4, 0x0E, 0x10, 0x00, 0xF1, 0x19, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, + 0xD4, 0x56, 0x10, 0x00, 0x7E, 0x4A, 0x01, 0x20, 0xA8, 0x4A, 0x01, 0x20, + 0x42, 0x44, 0x01, 0x20, + 0x2D, 0xE9, 0xF8, 0x43, 0x14, 0xF0, 0x53, 0xFE, 0x00, 0x90, 0x04, 0x21, + 0x68, 0x46, 0xFF, 0xF7, + 0xDA, 0xF9, 0xDF, 0xF8, 0xA0, 0x82, 0xC6, 0xB2, 0x01, 0x27, 0xD8, 0xF8, + 0x00, 0x00, 0xA6, 0x4C, + 0x90, 0xF8, 0x61, 0x00, 0x80, 0x09, 0x07, 0xFA, 0x00, 0xF5, 0xB1, 0x00, + 0x20, 0x46, 0x15, 0xF0, + 0x15, 0xFA, 0xA2, 0x48, 0x14, 0xF0, 0xD6, 0xFD, 0xA0, 0x48, 0xA0, 0xF1, + 0x34, 0x09, 0x87, 0x72, + 0x00, 0x27, 0x12, 0xE0, 0x9D, 0x48, 0xFF, 0xF7, 0xE7, 0xFD, 0x00, 0x20, + 0xD9, 0xF8, 0x2C, 0x10, + 0x08, 0xE0, 0x00, 0xBF, 0x54, 0xF8, 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, + 0x1A, 0x44, 0x44, 0xF8, + 0x20, 0x20, 0x40, 0x1C, 0xB0, 0x42, 0xF5, 0xDB, 0x7F, 0x1C, 0xAF, 0x42, + 0xEA, 0xDB, 0x00, 0x20, + 0x93, 0x4B, 0xD8, 0xF8, 0x00, 0x10, 0x08, 0xE0, 0x91, 0xF8, 0x61, 0x50, + 0x54, 0xF8, 0x20, 0x20, + 0xAD, 0x09, 0x2A, 0x41, 0x23, 0xF8, 0x10, 0x20, 0x40, 0x1C, 0xB0, 0x42, + 0xF4, 0xDB, 0xBD, 0xE8, + 0xF8, 0x83, 0x2D, 0xE9, 0xF0, 0x47, 0x05, 0x46, 0x00, 0x20, 0xFE, 0xF7, + 0x2A, 0xFC, 0x02, 0x20, + 0xFE, 0xF7, 0x27, 0xFC, 0x03, 0x20, 0xFE, 0xF7, 0x24, 0xFC, 0x86, 0x4E, + 0x00, 0x20, 0x30, 0x70, + 0x82, 0x48, 0x14, 0xF0, 0x97, 0xFD, 0x84, 0x48, 0x01, 0x24, 0x04, 0x70, + 0x7D, 0x4F, 0xDF, 0xF8, + 0x0C, 0x82, 0xDF, 0xF8, 0x0C, 0x92, 0x38, 0x68, 0x90, 0xF8, 0x60, 0x00, + 0x80, 0x07, 0x4F, 0xEA, + 0x05, 0x70, 0x0B, 0xD5, 0x00, 0x28, 0x11, 0xDA, 0xA8, 0x07, 0x09, 0xD5, + 0x34, 0x70, 0xFF, 0xF7, + 0xB6, 0xFE, 0x88, 0xF8, 0x00, 0x40, 0x89, 0xF8, 0x00, 0x40, 0x01, 0xE0, + 0x00, 0x28, 0x05, 0xDA, + 0x30, 0x78, 0x18, 0xB9, 0xFF, 0xF7, 0x24, 0xFE, 0x88, 0xF8, 0x00, 0x40, + 0x28, 0x06, 0x08, 0xD5, + 0x38, 0x68, 0x90, 0xF8, 0x2F, 0x0A, 0xC0, 0x07, 0x03, 0xD0, 0x72, 0x48, + 0x04, 0x70, 0xFF, 0xF7, + 0x77, 0xFF, 0xDF, 0xF8, 0xA8, 0x81, 0xA8, 0x07, 0x11, 0xD5, 0x30, 0x78, + 0xD0, 0xB9, 0x40, 0x46, + 0x14, 0xF0, 0x60, 0xFD, 0x88, 0xF8, 0x04, 0x40, 0x6B, 0x48, 0xFF, 0xF7, + 0xC3, 0xFD, 0x6A, 0x48, + 0x00, 0xF0, 0x23, 0xF8, 0x69, 0x49, 0x08, 0x70, 0x89, 0xF8, 0x00, 0x40, + 0x0A, 0xE0, 0x68, 0x07, + 0x08, 0xD5, 0x5E, 0x48, 0x14, 0xF0, 0x4E, 0xFD, 0x04, 0x21, 0x88, 0xF8, + 0x04, 0x10, 0x62, 0x48, + 0xFF, 0xF7, 0xB0, 0xFD, 0x38, 0x68, 0x90, 0xF8, 0x61, 0x04, 0x18, 0xB1, + 0xE8, 0x06, 0x01, 0xD5, + 0x00, 0xF0, 0x5E, 0xF8, 0x03, 0x20, 0xFE, 0xF7, 0xDF, 0xFB, 0x02, 0x20, + 0xFE, 0xF7, 0xDC, 0xFB, + 0xBD, 0xE8, 0xF0, 0x47, 0x00, 0x20, 0xFE, 0xF7, 0xD7, 0xBB, 0x2D, 0xE9, + 0xF0, 0x43, 0x4D, 0x49, + 0x4F, 0xF0, 0x00, 0x09, 0xCC, 0x46, 0x0F, 0x68, 0x4B, 0x46, 0x97, 0xF8, + 0x31, 0x20, 0x97, 0xF8, + 0x30, 0x60, 0x97, 0xF8, 0x60, 0x40, 0x02, 0xFB, 0x06, 0xF1, 0x09, 0xB2, + 0x64, 0x07, 0x37, 0xD5, + 0x4F, 0x4C, 0x24, 0x68, 0x25, 0x8E, 0x8D, 0x42, 0x32, 0xD1, 0x32, 0x34, + 0x28, 0xE0, 0x35, 0x46, + 0x20, 0xE0, 0x00, 0xBF, 0x34, 0xF8, 0x15, 0x10, 0x30, 0xF8, 0x15, 0x80, + 0xA1, 0xEB, 0x08, 0x01, + 0x09, 0xB2, 0x00, 0x29, 0x01, 0xDB, 0x88, 0x46, 0x01, 0xE0, 0xC1, 0xF1, + 0x00, 0x08, 0xE0, 0x45, + 0x07, 0xDD, 0x00, 0x29, 0x01, 0xDB, 0x8C, 0x46, 0x01, 0xE0, 0xC1, 0xF1, + 0x00, 0x0C, 0x0F, 0xFA, + 0x8C, 0xFC, 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0xB7, 0xF8, 0x63, 0x80, + 0x41, 0x45, 0x01, 0xDD, + 0x5B, 0x1C, 0x9B, 0xB2, 0x6D, 0x1E, 0xDD, 0xD1, 0x04, 0xEB, 0x46, 0x04, + 0x00, 0xEB, 0x46, 0x00, + 0x52, 0x1E, 0xD4, 0xD2, 0x97, 0xF8, 0x65, 0x00, 0x98, 0x42, 0x01, 0xD2, + 0x4F, 0xF0, 0x01, 0x09, + 0x34, 0x48, 0xA0, 0xF8, 0x00, 0xC0, 0x34, 0x48, 0x03, 0x80, 0x48, 0x46, + 0xBD, 0xE8, 0xF0, 0x83, + 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, 0x8C, 0x80, 0x01, 0x21, 0x45, 0x46, + 0xD8, 0xF8, 0x00, 0x00, + 0x00, 0xF2, 0x61, 0x40, 0xFF, 0xF7, 0xC7, 0xF8, 0x04, 0x46, 0x28, 0x68, + 0x01, 0x27, 0x1E, 0x4D, + 0x90, 0xF8, 0x61, 0x00, 0xC0, 0xF3, 0x01, 0x10, 0x07, 0xFA, 0x00, 0xF6, + 0xA1, 0x00, 0x28, 0x46, + 0x15, 0xF0, 0x04, 0xF9, 0x19, 0x48, 0x14, 0xF0, 0xC5, 0xFC, 0x18, 0x48, + 0xA0, 0xF1, 0x34, 0x09, + 0x47, 0x72, 0x00, 0x27, 0x11, 0xE0, 0x15, 0x48, 0xFF, 0xF7, 0xD6, 0xFC, + 0x00, 0x20, 0xD9, 0xF8, + 0x14, 0x10, 0x07, 0xE0, 0x55, 0xF8, 0x20, 0x20, 0x31, 0xF9, 0x10, 0x30, + 0x1A, 0x44, 0x45, 0xF8, + 0x20, 0x20, 0x40, 0x1C, 0xA0, 0x42, 0xF5, 0xDB, 0x7F, 0x1C, 0xB7, 0x42, + 0xEB, 0xDB, 0x00, 0x20, + 0x16, 0x4B, 0xD8, 0xF8, 0x00, 0x10, 0x09, 0xE0, 0x91, 0xF8, 0x61, 0x60, + 0x55, 0xF8, 0x20, 0x20, + 0xC6, 0xF3, 0x01, 0x16, 0x32, 0x41, 0x23, 0xF8, 0x10, 0x20, 0x40, 0x1C, + 0xA0, 0x42, 0xF3, 0xDB, + 0x44, 0xE5, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xD4, 0x56, 0x10, 0x00, + 0x28, 0x0F, 0x10, 0x00, + 0xFC, 0x4A, 0x01, 0x20, 0x68, 0x04, 0x10, 0x00, 0x78, 0x07, 0x10, 0x00, + 0x7A, 0x07, 0x10, 0x00, + 0x79, 0x07, 0x10, 0x00, 0x7C, 0x07, 0x10, 0x00, 0x42, 0x44, 0x01, 0x20, + 0x7D, 0x07, 0x10, 0x00, + 0x50, 0x07, 0x10, 0x00, 0x7E, 0x07, 0x10, 0x00, 0x80, 0x07, 0x10, 0x00, + 0xF4, 0x4A, 0x01, 0x20, + 0x10, 0xB5, 0x01, 0x46, 0x34, 0x22, 0xFE, 0x48, 0x15, 0xF0, 0x54, 0xF8, + 0x01, 0x21, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x20, 0xFE, 0xF7, 0x15, 0xBA, 0x38, 0xB5, 0x04, 0x46, + 0xF9, 0x48, 0xF8, 0x4D, + 0x20, 0x60, 0x20, 0x46, 0x14, 0xF0, 0x8B, 0xFC, 0x00, 0x22, 0x6B, 0x46, + 0x01, 0x21, 0x10, 0x46, + 0xFE, 0xF7, 0x50, 0xFA, 0x01, 0x21, 0x00, 0x20, 0xFE, 0xF7, 0x2F, 0xFA, + 0x28, 0x78, 0x00, 0x28, + 0x02, 0xD0, 0x10, 0xF0, 0x12, 0xFA, 0xEC, 0xE7, 0x38, 0xBD, 0x2D, 0xE9, + 0xFF, 0x41, 0x00, 0x24, + 0xDD, 0xE9, 0x0A, 0x76, 0x04, 0x21, 0x68, 0x46, 0xFF, 0xF7, 0x3D, 0xF8, + 0x05, 0x46, 0x08, 0x21, + 0x02, 0xA8, 0xFF, 0xF7, 0x38, 0xF8, 0x02, 0x46, 0x00, 0x20, 0x6F, 0xF0, + 0x7E, 0x0E, 0x14, 0xE0, + 0x00, 0x21, 0x00, 0xFB, 0x02, 0xF3, 0x0D, 0xE0, 0x07, 0xEB, 0x01, 0x0C, + 0x13, 0xF9, 0x0C, 0xC0, + 0xB4, 0x44, 0xF4, 0x45, 0x01, 0xDA, 0x01, 0x24, 0x03, 0xE0, 0xBC, 0xF1, + 0x7F, 0x0F, 0x00, 0xDD, + 0x02, 0x24, 0x49, 0x1C, 0x91, 0x42, 0xEF, 0xDB, 0x40, 0x1C, 0xA8, 0x42, + 0xE8, 0xDB, 0x20, 0x46, + 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xFF, 0x41, 0x0A, 0xA9, + 0x00, 0x24, 0x91, 0xE8, + 0xC0, 0x01, 0x04, 0x21, 0x68, 0x46, 0xFF, 0xF7, 0x0E, 0xF8, 0x05, 0x46, + 0x08, 0x21, 0x02, 0xA8, + 0xFF, 0xF7, 0x09, 0xF8, 0x01, 0x46, 0x00, 0x20, 0x08, 0xE0, 0x32, 0x56, + 0xD2, 0x19, 0x01, 0xD5, + 0x01, 0x24, 0x02, 0xE0, 0xFF, 0x2A, 0x00, 0xDD, 0x02, 0x24, 0x40, 0x1C, + 0xA8, 0x42, 0xF4, 0xDB, + 0x00, 0x20, 0x0A, 0xE0, 0x2A, 0x18, 0xB2, 0x56, 0x12, 0xEB, 0x08, 0x02, + 0x01, 0xD5, 0x01, 0x24, + 0x02, 0xE0, 0xFF, 0x2A, 0x00, 0xDD, 0x02, 0x24, 0x40, 0x1C, 0x88, 0x42, + 0xF2, 0xDB, 0x20, 0x46, + 0xCE, 0xE7, 0x2D, 0xE9, 0xF0, 0x4F, 0x8D, 0xB0, 0x14, 0xF0, 0x51, 0xFC, + 0x0C, 0x90, 0x14, 0xF0, + 0x50, 0xFC, 0xBD, 0x4E, 0x04, 0x46, 0x0D, 0x46, 0x30, 0x68, 0x90, 0xF8, + 0xE7, 0x00, 0x10, 0xF0, + 0x60, 0x0F, 0x03, 0xD0, 0x0C, 0x98, 0x11, 0xF0, 0x67, 0xF9, 0x0C, 0x90, + 0xDF, 0xF8, 0xD8, 0xA2, + 0x01, 0x21, 0xDA, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x31, 0x60, 0x90, 0xF8, + 0x30, 0x80, 0x06, 0xFB, + 0x08, 0xF0, 0x0B, 0x90, 0x06, 0xA8, 0x0E, 0xF0, 0x42, 0xFC, 0xB0, 0x4F, + 0x4F, 0xF0, 0x00, 0x0B, + 0xDF, 0xF8, 0xBC, 0x92, 0x39, 0x68, 0x06, 0x9B, 0x22, 0x46, 0x91, 0xF9, + 0x1B, 0x10, 0xCD, 0xF8, + 0x0C, 0xB0, 0xCD, 0xF8, 0x00, 0x90, 0xCD, 0xE9, 0x01, 0x31, 0x2B, 0x46, + 0x0C, 0x98, 0x11, 0xF0, + 0xC5, 0xF9, 0x06, 0x9B, 0x01, 0x20, 0xCD, 0xE9, 0x00, 0x93, 0xCD, 0xE9, + 0x02, 0xB0, 0x22, 0x46, + 0x2B, 0x46, 0x0C, 0x98, 0x11, 0xF0, 0xBA, 0xF9, 0x9D, 0x48, 0x34, 0x30, + 0x14, 0xF0, 0xB2, 0xFB, + 0x9B, 0x49, 0x05, 0x20, 0x34, 0x31, 0x08, 0x71, 0x08, 0x46, 0xFF, 0xF7, + 0x3D, 0xFF, 0x98, 0x48, + 0x02, 0x21, 0x80, 0x68, 0x00, 0x90, 0x0A, 0xA8, 0x0E, 0xF0, 0x11, 0xFC, + 0xDA, 0xF8, 0x00, 0x00, + 0xB0, 0xF9, 0xC2, 0xA1, 0xB0, 0xF9, 0xC4, 0x91, 0x0A, 0xEB, 0x09, 0x01, + 0x49, 0x10, 0x02, 0x91, + 0x90, 0xF8, 0xE8, 0x00, 0x80, 0x07, 0x09, 0xD4, 0xA8, 0xF1, 0x01, 0x00, + 0x70, 0x43, 0x00, 0x99, + 0x0B, 0x90, 0x43, 0x46, 0x32, 0x46, 0x08, 0x46, 0x00, 0xF0, 0x76, 0xFB, + 0xDD, 0xE9, 0x0A, 0x12, + 0x00, 0x98, 0x11, 0xF0, 0x8C, 0xFF, 0x80, 0x46, 0x02, 0x21, 0x0A, 0xA8, + 0x0E, 0xF0, 0x82, 0xFC, + 0x00, 0x26, 0xD0, 0x45, 0x01, 0xDC, 0xC8, 0x45, 0x09, 0xDA, 0x83, 0x48, + 0x02, 0x99, 0x00, 0x68, + 0xA8, 0xEB, 0x01, 0x01, 0xB0, 0xF8, 0xC6, 0x01, 0x91, 0xFB, 0xF0, 0xF0, + 0x46, 0xB2, 0x06, 0x98, + 0xCD, 0xE9, 0x00, 0x06, 0x22, 0x46, 0x2B, 0x46, 0x0C, 0x98, 0xFF, 0xF7, + 0x16, 0xFF, 0x01, 0x28, + 0x18, 0xD0, 0x02, 0x28, 0x1C, 0xD0, 0x38, 0x68, 0x79, 0x49, 0x2B, 0x46, + 0xC6, 0x76, 0x01, 0x20, + 0x06, 0x9A, 0x03, 0x90, 0x8D, 0xE8, 0x46, 0x00, 0x22, 0x46, 0x0C, 0x98, + 0x11, 0xF0, 0x5E, 0xF9, + 0x39, 0x68, 0xA5, 0x20, 0x88, 0x76, 0x01, 0x21, 0x06, 0xA8, 0x0E, 0xF0, + 0x53, 0xFC, 0x0D, 0xB0, + 0xBD, 0xE8, 0xF0, 0x8F, 0x39, 0x68, 0x81, 0xF8, 0x1B, 0xB0, 0x01, 0x21, + 0xB0, 0x20, 0x04, 0xE0, + 0x39, 0x68, 0xB1, 0x20, 0x81, 0xF8, 0x1B, 0xB0, 0x01, 0x21, 0x10, 0xF0, + 0xEF, 0xF8, 0xE7, 0xE7, + 0x2D, 0xE9, 0xF0, 0x4F, 0x64, 0x4F, 0x8D, 0xB0, 0x38, 0x68, 0x90, 0xF8, + 0x31, 0x60, 0x90, 0xF8, + 0x30, 0x80, 0x14, 0xF0, 0x94, 0xFB, 0x0B, 0x90, 0x14, 0xF0, 0x93, 0xFB, + 0x04, 0x46, 0x38, 0x68, + 0x0D, 0x46, 0x90, 0xF8, 0xE7, 0x00, 0x10, 0xF0, 0x60, 0x0F, 0x03, 0xD0, + 0x0B, 0x98, 0x11, 0xF0, + 0xAB, 0xF8, 0x0B, 0x90, 0x01, 0x21, 0x04, 0xA8, 0x0E, 0xF0, 0x91, 0xFB, + 0x57, 0x4F, 0x4F, 0xF0, + 0x00, 0x0A, 0xDF, 0xF8, 0x60, 0x91, 0x38, 0x68, 0x04, 0x9B, 0x90, 0xF9, + 0x1D, 0x20, 0xCD, 0xF8, + 0x0C, 0xA0, 0xCD, 0xF8, 0x00, 0x90, 0xCD, 0xE9, 0x01, 0x32, 0x22, 0x46, + 0x2B, 0x46, 0x0B, 0x98, + 0x11, 0xF0, 0x14, 0xF9, 0x04, 0x9B, 0x01, 0x21, 0xCD, 0xE9, 0x00, 0x93, + 0xCD, 0xE9, 0x02, 0xA1, + 0x22, 0x46, 0x2B, 0x46, 0x0B, 0x98, 0x11, 0xF0, 0x09, 0xF9, 0x45, 0x48, + 0x34, 0x30, 0x14, 0xF0, + 0x01, 0xFB, 0x43, 0x49, 0x06, 0x20, 0x34, 0x31, 0x08, 0x71, 0x08, 0x46, + 0xFF, 0xF7, 0x8C, 0xFE, + 0x3F, 0x48, 0x02, 0x21, 0x80, 0x68, 0x00, 0x90, 0x0A, 0xA8, 0x0E, 0xF0, + 0x60, 0xFB, 0x3E, 0x48, + 0x06, 0xFB, 0x08, 0xFB, 0x00, 0x68, 0xB0, 0xF9, 0xC8, 0x11, 0xB0, 0xF9, + 0xCA, 0x21, 0x11, 0x44, + 0x49, 0x10, 0x01, 0x91, 0x90, 0xF8, 0xE8, 0x00, 0x80, 0x07, 0x09, 0xD4, + 0xA8, 0xF1, 0x01, 0x00, + 0x00, 0x99, 0x06, 0xFB, 0x00, 0xFB, 0x43, 0x46, 0x32, 0x46, 0x08, 0x46, + 0x00, 0xF0, 0xC4, 0xFA, + 0x5A, 0x46, 0x0A, 0x99, 0x00, 0x98, 0x11, 0xF0, 0xDA, 0xFE, 0x80, 0x46, + 0x02, 0x21, 0x0A, 0xA8, + 0x0E, 0xF0, 0xD0, 0xFB, 0x2C, 0x48, 0x00, 0x26, 0x00, 0x68, 0xB0, 0xF9, + 0xC8, 0x21, 0x42, 0x45, + 0x03, 0xDB, 0xB0, 0xF9, 0xCA, 0x21, 0x42, 0x45, 0x07, 0xDD, 0x01, 0x9A, + 0xB0, 0xF8, 0xCC, 0x01, + 0xA8, 0xEB, 0x02, 0x01, 0x91, 0xFB, 0xF0, 0xF0, 0x46, 0xB2, 0x04, 0x98, + 0xCD, 0xE9, 0x00, 0x06, + 0x22, 0x46, 0x2B, 0x46, 0x0B, 0x98, 0xFF, 0xF7, 0x60, 0xFE, 0x4F, 0xF4, + 0x80, 0x71, 0x01, 0x28, + 0x17, 0xD0, 0x02, 0x28, 0x1A, 0xD0, 0x38, 0x68, 0x2B, 0x46, 0x46, 0x77, + 0x01, 0x20, 0x04, 0x9A, + 0xCD, 0xF8, 0x00, 0x90, 0x03, 0x90, 0xCD, 0xE9, 0x01, 0x26, 0x22, 0x46, + 0x0B, 0x98, 0x11, 0xF0, + 0xA5, 0xF8, 0x39, 0x68, 0xA5, 0x20, 0x08, 0x77, 0x01, 0x21, 0x04, 0xA8, + 0x0E, 0xF0, 0x9A, 0xFB, + 0x45, 0xE7, 0x3A, 0x68, 0xB0, 0x20, 0x82, 0xF8, 0x1D, 0xA0, 0x03, 0xE0, + 0x3A, 0x68, 0xB1, 0x20, + 0x82, 0xF8, 0x1D, 0xA0, 0x10, 0xF0, 0x3A, 0xF8, 0xEB, 0xE7, 0x2D, 0xE9, + 0xF0, 0x4F, 0x87, 0xB0, + 0x14, 0xF0, 0xE9, 0xFA, 0x05, 0x90, 0x14, 0xF0, 0xE8, 0xFA, 0x04, 0x46, + 0x0D, 0x46, 0x01, 0x21, + 0x04, 0xA8, 0x0E, 0xF0, 0xEC, 0xFA, 0x4F, 0xF0, 0x00, 0x0A, 0x56, 0x46, + 0x03, 0x4F, 0x0B, 0xE0, + 0x38, 0x0F, 0x10, 0x00, 0xE1, 0x20, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x50, 0x07, 0x10, 0x00, + 0x78, 0x8B, 0x01, 0x20, 0x08, 0x92, 0x01, 0x20, 0x38, 0x68, 0xDF, 0xF8, + 0x2C, 0x94, 0x04, 0x9A, + 0x90, 0xF9, 0x25, 0x10, 0xCD, 0xF8, 0x0C, 0xA0, 0xCD, 0xF8, 0x00, 0x90, + 0xCD, 0xE9, 0x01, 0x21, + 0x22, 0x46, 0x2B, 0x46, 0x05, 0x98, 0x11, 0xF0, 0x61, 0xF8, 0x01, 0x21, + 0x04, 0x9A, 0xCD, 0xF8, + 0x00, 0x90, 0x03, 0x91, 0xCD, 0xE9, 0x01, 0x26, 0x22, 0x46, 0x2B, 0x46, + 0x05, 0x98, 0x11, 0xF0, + 0x55, 0xF8, 0xFE, 0x48, 0x14, 0xF0, 0x4E, 0xFA, 0xFC, 0x48, 0x02, 0x21, + 0x41, 0x72, 0xFF, 0xF7, + 0xDB, 0xFD, 0xFA, 0x48, 0x02, 0x21, 0x34, 0x38, 0x46, 0x69, 0x06, 0xA8, + 0x0E, 0xF0, 0xAF, 0xFA, + 0xDF, 0xF8, 0xDC, 0xB3, 0x01, 0x21, 0xDB, 0xF8, 0x00, 0x00, 0x00, 0xF2, + 0x61, 0x40, 0xFE, 0xF7, + 0x2A, 0xFE, 0x02, 0x46, 0x30, 0x46, 0x06, 0x99, 0x11, 0xF0, 0x39, 0xFE, + 0x80, 0x46, 0x02, 0x21, + 0x06, 0xA8, 0x0E, 0xF0, 0x2F, 0xFB, 0xDB, 0xF8, 0x00, 0x10, 0x00, 0x26, + 0xB1, 0xF9, 0xDC, 0x21, + 0xB1, 0xF9, 0xDE, 0x31, 0xD0, 0x18, 0x4F, 0xEA, 0x60, 0x0C, 0x90, 0x45, + 0x01, 0xDC, 0x98, 0x45, + 0x06, 0xDA, 0xB1, 0xF8, 0xE0, 0x11, 0xA8, 0xEB, 0x0C, 0x00, 0x90, 0xFB, + 0xF1, 0xF0, 0x46, 0xB2, + 0x04, 0x98, 0xCD, 0xE9, 0x00, 0x06, 0x22, 0x46, 0x2B, 0x46, 0x05, 0x98, + 0xFF, 0xF7, 0xBD, 0xFD, + 0x01, 0x28, 0x1A, 0xD0, 0x02, 0x28, 0x1E, 0xD0, 0x38, 0x68, 0x2B, 0x46, + 0x80, 0xF8, 0x25, 0x60, + 0x01, 0x20, 0x04, 0x9A, 0xCD, 0xF8, 0x00, 0x90, 0x03, 0x90, 0xCD, 0xE9, + 0x01, 0x26, 0x22, 0x46, + 0x05, 0x98, 0x11, 0xF0, 0x03, 0xF8, 0x39, 0x68, 0xA5, 0x20, 0x81, 0xF8, + 0x24, 0x00, 0x01, 0x21, + 0x04, 0xA8, 0x0E, 0xF0, 0xF7, 0xFA, 0x07, 0xB0, 0xA2, 0xE6, 0x39, 0x68, + 0x81, 0xF8, 0x25, 0xA0, + 0x02, 0x21, 0xB0, 0x20, 0x04, 0xE0, 0x39, 0x68, 0xB1, 0x20, 0x81, 0xF8, + 0x25, 0xA0, 0x02, 0x21, + 0x0F, 0xF0, 0x94, 0xFF, 0xE7, 0xE7, 0x2D, 0xE9, 0xF0, 0x4F, 0xC9, 0x48, + 0x89, 0xB0, 0x00, 0x68, + 0x90, 0xF8, 0x31, 0x60, 0x90, 0xF8, 0x30, 0xB0, 0x14, 0xF0, 0x39, 0xFA, + 0x07, 0x90, 0x14, 0xF0, + 0x38, 0xFA, 0x04, 0x46, 0x0D, 0x46, 0x01, 0x21, 0x06, 0xA8, 0x0E, 0xF0, + 0x40, 0xFA, 0xDF, 0xF8, + 0x04, 0xA3, 0x02, 0xAB, 0x00, 0x27, 0xDA, 0xF8, 0x00, 0x00, 0x06, 0x9A, + 0x90, 0xF9, 0x20, 0x10, + 0x90, 0xF9, 0x1F, 0x00, 0x83, 0xE8, 0x83, 0x00, 0xB7, 0x48, 0x2B, 0x46, + 0xA0, 0x30, 0xCD, 0xE9, + 0x00, 0x02, 0x08, 0x90, 0x22, 0x46, 0x07, 0x98, 0x11, 0xF0, 0x0C, 0xF8, + 0x06, 0x99, 0xCD, 0xE9, + 0x01, 0x17, 0x01, 0x20, 0xCD, 0xE9, 0x03, 0x70, 0x08, 0x98, 0x00, 0x90, + 0x22, 0x46, 0x2B, 0x46, + 0x07, 0x98, 0x10, 0xF0, 0xFF, 0xFF, 0xAD, 0x48, 0x14, 0xF0, 0xAC, 0xF9, + 0xAB, 0x48, 0x03, 0x21, + 0x81, 0x71, 0xFF, 0xF7, 0x39, 0xFD, 0xA9, 0x48, 0x02, 0x21, 0x34, 0x38, + 0xD0, 0xE9, 0x06, 0x70, + 0x00, 0x90, 0xA7, 0x48, 0x00, 0x68, 0xB0, 0xF9, 0xCE, 0x91, 0xB0, 0xF9, + 0xD0, 0x81, 0x05, 0xA8, + 0x0E, 0xF0, 0x05, 0xFA, 0x09, 0xEB, 0x08, 0x00, 0x40, 0x10, 0x01, 0x90, + 0xA0, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x34, 0x01, 0x80, 0x07, 0x05, 0xD4, 0x39, 0x46, 0x32, 0x46, + 0x08, 0x46, 0x00, 0xF0, + 0x87, 0xF9, 0x76, 0x1E, 0x32, 0x46, 0x38, 0x46, 0x05, 0x99, 0x11, 0xF0, + 0x88, 0xFD, 0x00, 0x27, + 0x48, 0x45, 0x01, 0xDC, 0x40, 0x45, 0x08, 0xDA, 0x01, 0x99, 0x09, 0x1A, + 0x94, 0x48, 0x00, 0x68, + 0xB0, 0xF8, 0xD2, 0x01, 0x91, 0xFB, 0xF0, 0xF0, 0x47, 0xB2, 0x91, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0x34, 0x01, 0x80, 0x07, 0x06, 0xD4, 0x00, 0x99, 0x5A, 0x46, 0x08, 0x46, + 0x00, 0xF0, 0x68, 0xF9, + 0xAB, 0xF1, 0x01, 0x0B, 0x5A, 0x46, 0x05, 0x99, 0x00, 0x98, 0x11, 0xF0, + 0x68, 0xFD, 0x00, 0x26, + 0x48, 0x45, 0x01, 0xDC, 0x40, 0x45, 0x08, 0xDA, 0x01, 0x99, 0x09, 0x1A, + 0x84, 0x48, 0x00, 0x68, + 0xB0, 0xF8, 0xD4, 0x01, 0x91, 0xFB, 0xF0, 0xF0, 0x46, 0xB2, 0x02, 0x21, + 0x05, 0xA8, 0x0E, 0xF0, + 0x51, 0xFA, 0x06, 0x98, 0xCD, 0xE9, 0x00, 0x07, 0x02, 0x96, 0x22, 0x46, + 0x2B, 0x46, 0x07, 0x98, + 0xFF, 0xF7, 0x21, 0xFD, 0x01, 0x28, 0x1D, 0xD0, 0x02, 0x28, 0x24, 0xD0, + 0xDA, 0xF8, 0x00, 0x00, + 0x22, 0x46, 0x2B, 0x46, 0xC7, 0x77, 0x80, 0xF8, 0x20, 0x60, 0x01, 0x20, + 0x06, 0x99, 0xCD, 0xE9, + 0x03, 0x60, 0xCD, 0xE9, 0x01, 0x17, 0x08, 0x98, 0x00, 0x90, 0x07, 0x98, + 0x10, 0xF0, 0x82, 0xFF, + 0xDA, 0xF8, 0x00, 0x00, 0xA5, 0x21, 0x81, 0x77, 0x01, 0x21, 0x06, 0xA8, + 0x0E, 0xF0, 0x2A, 0xFA, + 0x09, 0xB0, 0xD5, 0xE5, 0xDA, 0xF8, 0x00, 0x10, 0x00, 0x20, 0xC8, 0x77, + 0x81, 0xF8, 0x20, 0x00, + 0x10, 0x21, 0xB2, 0x20, 0x07, 0xE0, 0xDA, 0xF8, 0x00, 0x10, 0x00, 0x20, + 0xC8, 0x77, 0x81, 0xF8, + 0x20, 0x00, 0x10, 0x21, 0xB3, 0x20, 0x0F, 0xF0, 0xC1, 0xFE, 0xE1, 0xE7, + 0x2D, 0xE9, 0xF0, 0x4F, + 0x87, 0xB0, 0x14, 0xF0, 0x6C, 0xF9, 0x83, 0x46, 0x14, 0xF0, 0x6B, 0xF9, + 0xDF, 0xF8, 0x70, 0x91, + 0x01, 0x21, 0xC8, 0x46, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x31, 0x60, + 0x05, 0xA8, 0x0E, 0xF0, + 0x6E, 0xF9, 0x58, 0x4D, 0x58, 0x4F, 0x05, 0x9A, 0x28, 0x68, 0x00, 0x24, + 0x23, 0x46, 0x90, 0xF9, + 0x23, 0x10, 0x90, 0xF9, 0x22, 0x00, 0x00, 0x97, 0xCD, 0xE9, 0x01, 0x20, + 0xCD, 0xE9, 0x03, 0x14, + 0x22, 0x46, 0x58, 0x46, 0x10, 0xF0, 0x3E, 0xFF, 0x05, 0x99, 0xCD, 0xE9, + 0x01, 0x14, 0x4F, 0xF0, + 0x01, 0x0A, 0x00, 0x97, 0xCD, 0xE9, 0x03, 0x4A, 0x00, 0x22, 0x13, 0x46, + 0x58, 0x46, 0x10, 0xF0, + 0x31, 0xFF, 0x46, 0x48, 0x14, 0xF0, 0xDE, 0xF8, 0x44, 0x49, 0x03, 0x20, + 0x08, 0x72, 0x08, 0x46, + 0xFF, 0xF7, 0x6A, 0xFC, 0x41, 0x48, 0x02, 0x21, 0x34, 0x38, 0x87, 0x6A, + 0x06, 0xA8, 0x0E, 0xF0, + 0x3E, 0xF9, 0xD8, 0xF8, 0x00, 0x00, 0xB0, 0xF9, 0xD6, 0x11, 0xB0, 0xF9, + 0xD8, 0x21, 0x90, 0xF8, + 0x84, 0x09, 0x11, 0x44, 0x01, 0xEB, 0xD1, 0x71, 0x4F, 0xEA, 0x61, 0x08, + 0x80, 0x07, 0x05, 0xD4, + 0x76, 0x1E, 0x39, 0x46, 0x32, 0x46, 0x08, 0x46, 0x00, 0xF0, 0xBA, 0xF8, + 0x32, 0x46, 0x38, 0x46, + 0x06, 0x99, 0x11, 0xF0, 0xBC, 0xFC, 0xD9, 0xF8, 0x00, 0x10, 0x00, 0x26, + 0x37, 0x46, 0xB1, 0xF9, + 0xD6, 0x21, 0x82, 0x42, 0x03, 0xDB, 0xB1, 0xF9, 0xD8, 0x21, 0x82, 0x42, + 0x06, 0xDD, 0xB1, 0xF8, + 0xDA, 0x11, 0xA8, 0xEB, 0x00, 0x00, 0x90, 0xFB, 0xF1, 0xF0, 0x46, 0xB2, + 0x02, 0x21, 0x06, 0xA8, + 0x0E, 0xF0, 0xA0, 0xF9, 0x05, 0x98, 0x00, 0x22, 0x8D, 0xE8, 0xC1, 0x00, + 0x13, 0x46, 0x58, 0x46, + 0xFF, 0xF7, 0x71, 0xFC, 0x01, 0x28, 0x1A, 0xD0, 0x02, 0x28, 0x28, 0x68, + 0x1E, 0xD0, 0x00, 0xF8, + 0x22, 0x6F, 0x00, 0x22, 0x44, 0x70, 0x20, 0x48, 0x05, 0x99, 0x98, 0x38, + 0x8D, 0xE8, 0x43, 0x00, + 0xCD, 0xE9, 0x03, 0x4A, 0x13, 0x46, 0x58, 0x46, 0x10, 0xF0, 0xD4, 0xFE, + 0x29, 0x68, 0xA5, 0x20, + 0x81, 0xF8, 0x21, 0x00, 0x01, 0x21, 0x05, 0xA8, 0x0E, 0xF0, 0x7C, 0xF9, + 0x83, 0xE6, 0x28, 0x68, + 0x40, 0x21, 0x00, 0xF8, 0x22, 0x4F, 0x44, 0x70, 0xB2, 0x20, 0x04, 0xE0, + 0x00, 0xF8, 0x22, 0x4F, + 0x40, 0x21, 0x44, 0x70, 0xB3, 0x20, 0x0F, 0xF0, 0x19, 0xFE, 0xE7, 0xE7, + 0x70, 0xB5, 0x04, 0x46, + 0x00, 0x20, 0xFD, 0xF7, 0xEE, 0xFE, 0x02, 0x20, 0xFD, 0xF7, 0xEB, 0xFE, + 0x0B, 0x49, 0x01, 0x20, + 0x08, 0x70, 0x07, 0x4D, 0x28, 0x68, 0x90, 0xF8, 0xC0, 0x01, 0x20, 0x40, + 0xC0, 0x07, 0x01, 0xD0, + 0xFF, 0xF7, 0x5F, 0xFC, 0x28, 0x68, 0x0B, 0xE0, 0x98, 0x98, 0x01, 0x20, + 0x6C, 0x0F, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x50, 0x07, 0x10, 0x00, 0xD0, 0x99, 0x01, 0x20, + 0x78, 0x07, 0x10, 0x00, + 0x90, 0xF8, 0xC0, 0x01, 0x80, 0x07, 0x03, 0xD5, 0xA0, 0x07, 0x01, 0xD5, + 0xFF, 0xF7, 0x00, 0xFD, + 0x28, 0x68, 0x90, 0xF8, 0xC0, 0x11, 0xC9, 0x06, 0x06, 0xD5, 0x90, 0xF8, + 0x61, 0x04, 0x18, 0xB1, + 0xE0, 0x06, 0x01, 0xD5, 0xFF, 0xF7, 0xA9, 0xFD, 0x28, 0x68, 0x90, 0xF8, + 0xC0, 0x01, 0x40, 0x07, + 0x03, 0xD5, 0x60, 0x07, 0x01, 0xD5, 0xFF, 0xF7, 0x46, 0xFE, 0x28, 0x68, + 0x90, 0xF8, 0xC0, 0x01, + 0x00, 0x07, 0x03, 0xD5, 0x20, 0x07, 0x01, 0xD5, 0xFF, 0xF7, 0x10, 0xFF, + 0x00, 0x20, 0xFD, 0xF7, + 0xC3, 0xFE, 0x02, 0x20, 0xFD, 0xF7, 0xC0, 0xFE, 0xE0, 0x07, 0x04, 0xD0, + 0xBD, 0xE8, 0x70, 0x40, + 0x01, 0x20, 0x01, 0xF0, 0x75, 0xBA, 0x70, 0xBD, 0xF0, 0xB5, 0x00, 0x26, + 0x35, 0x46, 0x0C, 0xE0, + 0x01, 0x24, 0x07, 0xE0, 0x05, 0xFB, 0x03, 0x47, 0x64, 0x1C, 0x31, 0xF8, + 0x17, 0x70, 0x20, 0xF8, + 0x16, 0x70, 0x76, 0x1C, 0x9C, 0x42, 0xF5, 0xDB, 0x6D, 0x1C, 0x95, 0x42, + 0xF0, 0xDB, 0xF0, 0xBD, + 0x30, 0xB5, 0x00, 0x24, 0x01, 0x23, 0x05, 0xE0, 0x31, 0xF8, 0x13, 0x50, + 0x20, 0xF8, 0x14, 0x50, + 0x5B, 0x1C, 0x64, 0x1C, 0x93, 0x42, 0xF7, 0xDB, 0x30, 0xBD, 0x00, 0x00, + 0x70, 0xB5, 0x7E, 0x4D, + 0x4F, 0xF4, 0x25, 0x74, 0x21, 0x46, 0x28, 0x68, 0xFE, 0xF7, 0x17, 0xFC, + 0x00, 0x21, 0x1F, 0x20, + 0x0D, 0xF1, 0xFE, 0xF8, 0x22, 0x46, 0x29, 0x68, 0xBD, 0xE8, 0x70, 0x40, + 0x1F, 0x23, 0x77, 0x48, + 0xFE, 0xF7, 0xCA, 0xBA, 0x70, 0xB5, 0x76, 0x4D, 0x40, 0xF2, 0xAF, 0x14, + 0x21, 0x46, 0x28, 0x68, + 0xFE, 0xF7, 0x03, 0xFC, 0x00, 0x21, 0x1A, 0x20, 0x0D, 0xF1, 0xEA, 0xF8, + 0x22, 0x46, 0x29, 0x68, + 0xBD, 0xE8, 0x70, 0x40, 0x1A, 0x23, 0x6F, 0x48, 0xFE, 0xF7, 0xB6, 0xBA, + 0x2D, 0xE9, 0xF0, 0x41, + 0xDF, 0xF8, 0xB4, 0x81, 0x05, 0x1D, 0x0E, 0x46, 0x29, 0x46, 0x40, 0x46, + 0xFE, 0xF7, 0xED, 0xFB, + 0x30, 0x68, 0x6A, 0x4A, 0x00, 0xEB, 0x85, 0x03, 0x93, 0x42, 0x01, 0xD2, + 0x1B, 0x23, 0x13, 0xE0, + 0x67, 0x49, 0x8B, 0x42, 0x13, 0xD2, 0x90, 0x42, 0x0D, 0xD2, 0x44, 0x46, + 0x11, 0x1A, 0x8F, 0x08, + 0x90, 0x46, 0x1B, 0x23, 0x3A, 0x46, 0x21, 0x46, 0xFE, 0xF7, 0x96, 0xFA, + 0xEA, 0x1B, 0x04, 0xEB, + 0x87, 0x01, 0x1C, 0x23, 0x15, 0xE0, 0x1C, 0x23, 0x2A, 0x46, 0x41, 0x46, + 0x12, 0xE0, 0x5D, 0x4A, + 0x93, 0x42, 0x19, 0xD2, 0x88, 0x42, 0x15, 0xD2, 0x44, 0x46, 0x88, 0x46, + 0x09, 0x1A, 0x8F, 0x08, + 0x1C, 0x23, 0x3A, 0x46, 0x21, 0x46, 0xFE, 0xF7, 0x7F, 0xFA, 0xEA, 0x1B, + 0x04, 0xEB, 0x87, 0x01, + 0x1D, 0x23, 0x40, 0x46, 0xFE, 0xF7, 0x78, 0xFA, 0x30, 0x68, 0x00, 0xEB, + 0x85, 0x00, 0x30, 0x60, + 0xBD, 0xE8, 0xF0, 0x81, 0x1D, 0x23, 0xDF, 0xE7, 0x90, 0x42, 0x0D, 0xD2, + 0x47, 0x46, 0x11, 0x1A, + 0x8C, 0x08, 0x90, 0x46, 0x1D, 0x23, 0x22, 0x46, 0x39, 0x46, 0xFE, 0xF7, + 0x65, 0xFA, 0x2A, 0x1B, + 0x07, 0xEB, 0x84, 0x01, 0x1E, 0x23, 0xE4, 0xE7, 0x1E, 0x23, 0xCD, 0xE7, + 0xF8, 0xB5, 0x42, 0x4C, + 0x45, 0x48, 0x00, 0x90, 0x10, 0x34, 0x02, 0x20, 0xFD, 0xF7, 0xF3, 0xFD, + 0x00, 0x21, 0x1B, 0x20, + 0x0D, 0xF1, 0x7E, 0xF8, 0x00, 0x21, 0x1C, 0x20, 0x0D, 0xF1, 0x7A, 0xF8, + 0x00, 0x21, 0x1D, 0x20, + 0x0D, 0xF1, 0x76, 0xF8, 0x00, 0x21, 0x1E, 0x20, 0x0D, 0xF1, 0x72, 0xF8, + 0x10, 0x21, 0x20, 0x46, + 0x14, 0xF0, 0x72, 0xFB, 0x00, 0x20, 0x20, 0x80, 0xA0, 0x70, 0x2F, 0x4D, + 0x01, 0x20, 0xE0, 0x70, + 0x28, 0x68, 0xC1, 0x8A, 0xA1, 0x80, 0x80, 0x8A, 0xE0, 0x80, 0x04, 0x20, + 0x69, 0x46, 0xFF, 0xF7, + 0x7D, 0xFF, 0x01, 0x23, 0x00, 0x22, 0x21, 0x46, 0x10, 0x20, 0x11, 0xF0, + 0x37, 0xF8, 0x06, 0x46, + 0x69, 0x46, 0xFF, 0xF7, 0x73, 0xFF, 0x01, 0x23, 0x00, 0x22, 0x21, 0x46, + 0x11, 0x20, 0x11, 0xF0, + 0x2D, 0xF8, 0x69, 0x46, 0x30, 0x46, 0xFF, 0xF7, 0x69, 0xFF, 0x28, 0x68, + 0x90, 0xF8, 0x61, 0x04, + 0x48, 0xB1, 0x01, 0x23, 0x00, 0x22, 0x21, 0x46, 0x14, 0x20, 0x11, 0xF0, + 0x1F, 0xF8, 0x69, 0x46, + 0x30, 0x46, 0xFF, 0xF7, 0x5B, 0xFF, 0x28, 0x68, 0x90, 0xF8, 0x50, 0x12, + 0xC9, 0x07, 0x03, 0xD1, + 0x90, 0xF8, 0x80, 0x02, 0xC0, 0x07, 0x09, 0xD0, 0x01, 0x23, 0x00, 0x22, + 0x21, 0x46, 0x12, 0x20, + 0x11, 0xF0, 0x0C, 0xF8, 0x69, 0x46, 0x30, 0x46, 0xFF, 0xF7, 0x48, 0xFF, + 0x01, 0x23, 0x00, 0x22, + 0x21, 0x46, 0x13, 0x20, 0x11, 0xF0, 0x02, 0xF8, 0x69, 0x46, 0x30, 0x46, + 0xFF, 0xF7, 0x3E, 0xFF, + 0x28, 0x68, 0x90, 0xF8, 0x2F, 0x0A, 0xC0, 0x07, 0x09, 0xD0, 0x01, 0x23, + 0x00, 0x22, 0x21, 0x46, + 0x17, 0x20, 0x10, 0xF0, 0xF3, 0xFF, 0x69, 0x46, 0x30, 0x46, 0xFF, 0xF7, + 0x2F, 0xFF, 0x02, 0x20, + 0xFD, 0xF7, 0x9A, 0xFD, 0xF8, 0xBD, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0xF0, 0xEF, 0x01, 0x00, + 0x50, 0x07, 0x10, 0x00, 0xF0, 0x9F, 0x01, 0x00, 0xD4, 0x56, 0x10, 0x00, + 0xF0, 0xBF, 0x01, 0x00, + 0xF0, 0xCF, 0x01, 0x00, 0xF0, 0xDF, 0x01, 0x00, 0xF0, 0xAF, 0x01, 0x00, + 0x10, 0xB5, 0x01, 0x46, + 0x34, 0x22, 0xFE, 0x48, 0x14, 0xF0, 0xBE, 0xFA, 0x01, 0x21, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x20, + 0xFD, 0xF7, 0x7F, 0xBC, 0x70, 0xB5, 0x86, 0xB0, 0x06, 0x46, 0x68, 0x46, + 0x13, 0xF0, 0xD2, 0xFE, + 0xF7, 0x48, 0x00, 0x90, 0x02, 0x2E, 0x15, 0xD0, 0x07, 0x20, 0x8D, 0xF8, + 0x04, 0x00, 0xF3, 0x4C, + 0x68, 0x46, 0x13, 0xF0, 0xEC, 0xFE, 0x00, 0x22, 0x04, 0xAB, 0x01, 0x21, + 0x10, 0x46, 0xFD, 0xF7, + 0xB1, 0xFC, 0x01, 0x21, 0x00, 0x20, 0xFD, 0xF7, 0x90, 0xFC, 0x20, 0x78, + 0x30, 0xB1, 0x0F, 0xF0, + 0x74, 0xFC, 0xED, 0xE7, 0x03, 0x20, 0x8D, 0xF8, 0x09, 0x00, 0xE8, 0xE7, + 0xE9, 0x4D, 0x02, 0x2E, + 0x09, 0xD0, 0x13, 0xF0, 0x0C, 0xFF, 0xA8, 0x61, 0x13, 0xF0, 0x0B, 0xFF, + 0xC5, 0xE9, 0x10, 0x01, + 0xA0, 0x68, 0x06, 0xB0, 0x70, 0xBD, 0x13, 0xF0, 0x06, 0xFF, 0xA8, 0x61, + 0x13, 0xF0, 0x05, 0xFF, + 0xC5, 0xE9, 0x10, 0x01, 0x60, 0x69, 0xF4, 0xE7, 0x2D, 0xE9, 0xF0, 0x41, + 0xDD, 0x4C, 0x01, 0x25, + 0x60, 0x38, 0xD4, 0xE9, 0x10, 0x23, 0xA6, 0x69, 0x09, 0x28, 0x6F, 0xD2, + 0xDF, 0xE8, 0x00, 0xF0, + 0x05, 0x0F, 0x1E, 0x28, 0x37, 0x41, 0x50, 0x5A, 0x6A, 0x00, 0x32, 0x46, + 0x00, 0x23, 0x08, 0x46, + 0x00, 0xF0, 0x51, 0xFA, 0x85, 0x40, 0x60, 0x68, 0x05, 0x43, 0x65, 0x60, + 0x5E, 0xE0, 0x08, 0x46, + 0x00, 0xF0, 0x49, 0xFA, 0x02, 0x46, 0x01, 0x20, 0x00, 0x21, 0x14, 0xF0, + 0xDF, 0xF9, 0xD4, 0xE9, + 0x08, 0x23, 0x10, 0x43, 0x19, 0x43, 0xC4, 0xE9, 0x08, 0x01, 0x4F, 0xE0, + 0x32, 0x46, 0x00, 0x23, + 0x08, 0x46, 0x00, 0xF0, 0x38, 0xFA, 0x85, 0x40, 0xE0, 0x68, 0x05, 0x43, + 0xE5, 0x60, 0x45, 0xE0, + 0x08, 0x46, 0x00, 0xF0, 0x30, 0xFA, 0x02, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x14, 0xF0, 0xC6, 0xF9, + 0xD4, 0xE9, 0x0C, 0x23, 0x10, 0x43, 0x19, 0x43, 0xC4, 0xE9, 0x0C, 0x01, + 0x36, 0xE0, 0x32, 0x46, + 0x00, 0x23, 0x08, 0x46, 0x00, 0xF0, 0x1F, 0xFA, 0x85, 0x40, 0xA0, 0x68, + 0x05, 0x43, 0xA5, 0x60, + 0x2C, 0xE0, 0x08, 0x46, 0x00, 0xF0, 0x17, 0xFA, 0x02, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x14, 0xF0, + 0xAD, 0xF9, 0xD4, 0xE9, 0x0A, 0x23, 0x10, 0x43, 0x19, 0x43, 0xC4, 0xE9, + 0x0A, 0x01, 0x1D, 0xE0, + 0x32, 0x46, 0x00, 0x23, 0x08, 0x46, 0x00, 0xF0, 0x06, 0xFA, 0x85, 0x40, + 0x20, 0x69, 0x05, 0x43, + 0x25, 0x61, 0x13, 0xE0, 0x08, 0x46, 0x00, 0xF0, 0xFE, 0xF9, 0x01, 0x23, + 0x02, 0x46, 0x00, 0x21, + 0x18, 0x46, 0x14, 0xF0, 0x93, 0xF9, 0xD4, 0xE9, 0x0E, 0x23, 0x10, 0x43, + 0x19, 0x43, 0xC4, 0xE9, + 0x0E, 0x01, 0x03, 0xE0, 0x60, 0x69, 0x8D, 0x40, 0x05, 0x43, 0x65, 0x61, + 0x20, 0x68, 0x40, 0x1C, + 0x20, 0x60, 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xF0, 0x41, 0x17, 0x46, + 0x04, 0x46, 0x0D, 0x46, + 0x00, 0x26, 0x09, 0xE0, 0xE0, 0x07, 0x03, 0xD0, 0x31, 0x46, 0x38, 0x46, + 0x0F, 0xF0, 0xBE, 0xFB, + 0x76, 0x1C, 0x6D, 0x08, 0x4F, 0xEA, 0x34, 0x04, 0x54, 0xEA, 0x05, 0x00, + 0xF2, 0xD1, 0xE8, 0xE7, + 0x70, 0xB5, 0x94, 0x4C, 0xE1, 0x68, 0x60, 0x68, 0xD4, 0xE9, 0x0C, 0x65, + 0x40, 0xEA, 0x01, 0x03, + 0xD4, 0xE9, 0x08, 0x21, 0x29, 0x43, 0x25, 0x69, 0x32, 0x43, 0x9D, 0x43, + 0x25, 0x61, 0xD4, 0xE9, + 0x0E, 0x35, 0x93, 0x43, 0x8D, 0x43, 0xC4, 0xE9, 0x0E, 0x35, 0x21, 0x68, + 0x00, 0x29, 0x2C, 0xD0, + 0x60, 0x22, 0x00, 0x21, 0xFF, 0xF7, 0xCF, 0xFF, 0xD4, 0xE9, 0x08, 0x01, + 0x61, 0x22, 0xFF, 0xF7, + 0xCA, 0xFF, 0x62, 0x22, 0x00, 0x21, 0xE0, 0x68, 0xFF, 0xF7, 0xC5, 0xFF, + 0xD4, 0xE9, 0x0C, 0x01, + 0x63, 0x22, 0xFF, 0xF7, 0xC0, 0xFF, 0x64, 0x22, 0x00, 0x21, 0xA0, 0x68, + 0xFF, 0xF7, 0xBB, 0xFF, + 0xD4, 0xE9, 0x0A, 0x01, 0x65, 0x22, 0xFF, 0xF7, 0xB6, 0xFF, 0x66, 0x22, + 0x00, 0x21, 0x20, 0x69, + 0xFF, 0xF7, 0xB1, 0xFF, 0xD4, 0xE9, 0x0E, 0x01, 0x67, 0x22, 0xFF, 0xF7, + 0xAC, 0xFF, 0x60, 0x69, + 0xBD, 0xE8, 0x70, 0x40, 0x68, 0x22, 0x00, 0x21, 0xA5, 0xE7, 0x70, 0xBD, + 0x2D, 0xE9, 0xF0, 0x5F, + 0x83, 0x46, 0x4F, 0xF0, 0x00, 0x0A, 0x13, 0xF0, 0x1A, 0xFE, 0x04, 0x46, + 0x13, 0xF0, 0x1B, 0xFE, + 0x40, 0xEA, 0x04, 0x06, 0x13, 0xF0, 0x15, 0xFE, 0x07, 0x46, 0x88, 0x46, + 0x13, 0xF0, 0x15, 0xFE, + 0x41, 0xEA, 0x08, 0x05, 0x67, 0x49, 0x40, 0xEA, 0x07, 0x04, 0x8E, 0x61, + 0xC1, 0xE9, 0x10, 0x45, + 0xFD, 0xF7, 0x0E, 0xFD, 0x00, 0xF0, 0xFF, 0x08, 0xFD, 0xF7, 0x0C, 0xFD, + 0x00, 0xF0, 0xFF, 0x09, + 0xFD, 0xF7, 0x19, 0xFE, 0x00, 0x27, 0x26, 0xE0, 0x01, 0x20, 0xB8, 0x40, + 0x30, 0x42, 0x21, 0xD0, + 0xF8, 0xB2, 0x00, 0x21, 0xFD, 0xF7, 0x17, 0xFE, 0x41, 0x07, 0x05, 0xD5, + 0x5F, 0xEA, 0xCB, 0x61, + 0x02, 0xD5, 0x51, 0x46, 0x62, 0x20, 0x0F, 0xE0, 0xC1, 0x07, 0x05, 0xD0, + 0x5F, 0xEA, 0x4B, 0x71, + 0x02, 0xD5, 0x51, 0x46, 0x60, 0x20, 0x07, 0xE0, 0x1B, 0xF0, 0xC0, 0x0F, + 0x06, 0xD0, 0x10, 0xF0, + 0x0A, 0x0F, 0x03, 0xD0, 0x51, 0x46, 0x64, 0x20, 0xFF, 0xF7, 0xDE, 0xFE, + 0x0A, 0xF1, 0x01, 0x00, + 0x00, 0xF0, 0xFF, 0x0A, 0x7F, 0x1C, 0x47, 0x45, 0xD6, 0xDB, 0xFD, 0xF7, + 0xEC, 0xFD, 0x00, 0x27, + 0x3E, 0x46, 0x29, 0xE0, 0x32, 0x46, 0x01, 0x20, 0x00, 0x21, 0x14, 0xF0, + 0xCF, 0xF8, 0x20, 0x40, + 0x29, 0x40, 0x08, 0x43, 0x1F, 0xD0, 0xF0, 0xB2, 0x01, 0x21, 0xFD, 0xF7, + 0xE4, 0xFD, 0x41, 0x07, + 0x05, 0xD5, 0x5F, 0xEA, 0x8B, 0x61, 0x02, 0xD5, 0x39, 0x46, 0x63, 0x20, + 0x0F, 0xE0, 0xC1, 0x07, + 0x05, 0xD0, 0x5F, 0xEA, 0x0B, 0x71, 0x02, 0xD5, 0x39, 0x46, 0x61, 0x20, + 0x07, 0xE0, 0x1B, 0xF4, + 0xC0, 0x7F, 0x06, 0xD0, 0x10, 0xF0, 0x0A, 0x0F, 0x03, 0xD0, 0x39, 0x46, + 0x65, 0x20, 0xFF, 0xF7, + 0xAB, 0xFE, 0x7F, 0x1C, 0xFF, 0xB2, 0x76, 0x1C, 0x4E, 0x45, 0xD3, 0xDD, + 0xBD, 0xE8, 0xF0, 0x5F, + 0xFD, 0xF7, 0xB9, 0xBD, 0x30, 0x48, 0x02, 0x68, 0x12, 0xF8, 0xD3, 0x1F, + 0xD0, 0x78, 0x00, 0xF0, + 0x1F, 0x00, 0x40, 0x1C, 0x41, 0x43, 0x48, 0x00, 0xC0, 0xEB, 0x40, 0x20, + 0x40, 0x10, 0x70, 0x47, + 0x2D, 0xE9, 0xFC, 0x5F, 0x07, 0x46, 0x00, 0x20, 0xCD, 0xE9, 0x00, 0x00, + 0x1C, 0x46, 0x92, 0x46, + 0x0E, 0x46, 0xFF, 0xF7, 0xE7, 0xFF, 0x00, 0xEB, 0x04, 0x08, 0x0C, 0x98, + 0x80, 0x07, 0x50, 0xD5, + 0x00, 0x24, 0x4C, 0xE0, 0x4F, 0xF0, 0x00, 0x09, 0x4F, 0xF0, 0xFF, 0x3B, + 0x4D, 0x46, 0x27, 0xE0, + 0x05, 0xFB, 0x06, 0x40, 0x3A, 0xF9, 0x10, 0x20, 0x42, 0x45, 0x20, 0xD2, + 0x09, 0xF1, 0x01, 0x09, + 0xBB, 0xF1, 0xFF, 0x3F, 0x00, 0xD1, 0xAB, 0x46, 0x79, 0x1E, 0x8D, 0x42, + 0x17, 0xD1, 0xB9, 0xF1, + 0x01, 0x0F, 0x14, 0xD1, 0x71, 0x1E, 0x8C, 0x42, 0x04, 0xD1, 0x29, 0x46, + 0x66, 0x20, 0xFF, 0xF7, + 0x63, 0xFE, 0x0C, 0xE0, 0x0A, 0xEB, 0x40, 0x00, 0xB0, 0xF9, 0x02, 0x20, + 0x42, 0x45, 0x04, 0xD3, + 0x2C, 0xB1, 0x30, 0xF9, 0x02, 0x1C, 0x41, 0x45, 0x01, 0xD2, 0x4F, 0xF0, + 0x00, 0x09, 0x6D, 0x1C, + 0xBD, 0x42, 0xD5, 0xD3, 0xA7, 0xEB, 0x0B, 0x01, 0x49, 0x45, 0x17, 0xD8, + 0x21, 0x46, 0x67, 0x20, + 0xFF, 0xF7, 0x4A, 0xFE, 0x01, 0x20, 0x22, 0x46, 0x00, 0x21, 0x07, 0xE0, + 0x7C, 0x0F, 0x10, 0x00, + 0x0D, 0x2C, 0x00, 0x00, 0x70, 0x04, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x14, 0xF0, 0x3E, 0xF8, + 0xDD, 0xE9, 0x00, 0x23, 0x10, 0x43, 0x19, 0x43, 0xCD, 0xE9, 0x00, 0x01, + 0x64, 0x1C, 0xB4, 0x42, + 0xB0, 0xD3, 0x0C, 0x98, 0xC0, 0x07, 0x25, 0xD0, 0x00, 0x25, 0x21, 0xE0, + 0x4F, 0xF0, 0x00, 0x09, + 0x4C, 0x46, 0x13, 0xE0, 0x05, 0xFB, 0x06, 0x41, 0x3A, 0xF9, 0x11, 0x10, + 0x41, 0x45, 0x0C, 0xD2, + 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x14, 0xF0, 0x21, 0xF8, 0xDD, 0xE9, + 0x00, 0x23, 0x10, 0x40, + 0x19, 0x40, 0x08, 0x43, 0x01, 0xD1, 0x09, 0xF1, 0x01, 0x09, 0x64, 0x1C, + 0xB4, 0x42, 0xE9, 0xD3, + 0xB9, 0xF1, 0x00, 0x0F, 0x03, 0xD0, 0x29, 0x46, 0x66, 0x20, 0xFF, 0xF7, + 0x0D, 0xFE, 0x6D, 0x1C, + 0xBD, 0x42, 0xDB, 0xD3, 0xBD, 0xE8, 0xFC, 0x9F, 0x2D, 0xE9, 0xFF, 0x47, + 0x04, 0x46, 0x00, 0x20, + 0xFD, 0xF7, 0x27, 0xFB, 0x4C, 0x49, 0x4F, 0xF0, 0x01, 0x09, 0x81, 0xF8, + 0x00, 0x90, 0x00, 0xF0, + 0x7D, 0xF8, 0x14, 0xF0, 0x0C, 0x0F, 0x09, 0xD1, 0xE0, 0x06, 0x07, 0xD4, + 0xA0, 0x06, 0x05, 0xD4, + 0x60, 0x06, 0x03, 0xD4, 0xE0, 0x05, 0x01, 0xD4, 0x20, 0x06, 0x02, 0xD5, + 0x20, 0x46, 0xFF, 0xF7, + 0xC5, 0xFE, 0x42, 0x4E, 0xA0, 0x07, 0x1C, 0xD0, 0x01, 0x20, 0xFF, 0xF7, + 0xAB, 0xFD, 0x05, 0x46, + 0x13, 0xF0, 0xDD, 0xFC, 0x01, 0x90, 0x13, 0xF0, 0xDC, 0xFC, 0xCD, 0xE9, + 0x02, 0x01, 0x04, 0x21, + 0x01, 0xA8, 0xFE, 0xF7, 0x68, 0xF8, 0x07, 0x46, 0x08, 0x21, 0x02, 0xA8, + 0xFE, 0xF7, 0x63, 0xF8, + 0x01, 0x46, 0x00, 0x94, 0x30, 0x68, 0x2A, 0x46, 0x90, 0xF8, 0xDA, 0x30, + 0x38, 0x46, 0xFF, 0xF7, + 0x37, 0xFF, 0x14, 0xF4, 0xC0, 0x6F, 0x26, 0xD0, 0x30, 0x68, 0x90, 0xF8, + 0x61, 0x04, 0x10, 0xB3, + 0x00, 0x25, 0xFF, 0xF7, 0x1F, 0xFF, 0x31, 0x68, 0xB0, 0x46, 0x91, 0xF8, + 0xDB, 0x10, 0x0F, 0x18, + 0x02, 0x20, 0xFF, 0xF7, 0x7F, 0xFD, 0x06, 0x46, 0x5F, 0xF0, 0x00, 0x04, + 0xD8, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0x61, 0x14, 0x09, 0xFA, 0x04, 0xF0, 0x01, 0x42, 0x09, 0xD0, + 0x6D, 0x1C, 0x36, 0xF9, + 0x14, 0x00, 0xED, 0xB2, 0xB8, 0x42, 0x03, 0xD2, 0x29, 0x46, 0x68, 0x20, + 0xFF, 0xF7, 0xA4, 0xFD, + 0x64, 0x1C, 0x04, 0x2C, 0xEA, 0xDB, 0xFF, 0xF7, 0x33, 0xFE, 0x04, 0xB0, + 0x00, 0x20, 0xBD, 0xE8, + 0xF0, 0x47, 0xFD, 0xF7, 0xD9, 0xBA, 0x2D, 0xE9, 0xF0, 0x41, 0x16, 0x46, + 0x1F, 0x46, 0x80, 0x46, + 0x4F, 0xF0, 0xFF, 0x35, 0x00, 0x24, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x13, 0xF0, 0x8E, 0xFF, + 0x30, 0x40, 0x39, 0x40, 0x08, 0x43, 0x04, 0xD0, 0x6D, 0x1C, 0x45, 0x45, + 0x01, 0xD1, 0x20, 0x46, + 0xFF, 0xE5, 0x64, 0x1C, 0x40, 0x2C, 0xEE, 0xD3, 0x00, 0x20, 0xFA, 0xE5, + 0x0C, 0x48, 0x00, 0x21, + 0x01, 0x61, 0x41, 0x60, 0x81, 0x60, 0xC1, 0x60, 0xC0, 0xE9, 0x0E, 0x11, + 0xC0, 0xE9, 0x08, 0x11, + 0xC0, 0xE9, 0x0A, 0x11, 0x41, 0x61, 0x01, 0x60, 0xC0, 0xE9, 0x0C, 0x11, + 0x41, 0xF2, 0xC8, 0x11, + 0x04, 0x48, 0x14, 0xF0, 0x43, 0xB8, 0x00, 0x00, 0x78, 0x07, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0x70, 0x04, 0x10, 0x00, 0x78, 0x8B, 0x01, 0x20, 0x11, 0x49, 0x08, 0x60, + 0x4F, 0xF4, 0x00, 0x51, + 0x00, 0x20, 0xFD, 0xF7, 0x9E, 0xB9, 0x38, 0xB5, 0xAF, 0xF2, 0x13, 0x00, + 0xFE, 0xF7, 0xAB, 0xFB, + 0x00, 0x22, 0x4F, 0xF4, 0x00, 0x54, 0x6B, 0x46, 0x21, 0x46, 0x10, 0x46, + 0xFD, 0xF7, 0xDA, 0xF9, + 0x21, 0x46, 0x00, 0x20, 0xFD, 0xF7, 0xB9, 0xF9, 0x06, 0x48, 0xA5, 0x22, + 0x01, 0x68, 0x04, 0x48, + 0x0A, 0x74, 0x00, 0x68, 0x20, 0xF0, 0x7F, 0x42, 0x4A, 0x61, 0xFE, 0xF7, + 0xB2, 0xFB, 0x38, 0xBD, + 0xB8, 0x04, 0x10, 0x00, 0x50, 0x07, 0x10, 0x00, 0x02, 0x00, 0x04, 0xD0, + 0x01, 0x2A, 0x04, 0xD0, + 0x02, 0x28, 0x03, 0xD1, 0x04, 0xE0, 0x01, 0x20, 0x00, 0xE0, 0x04, 0x20, + 0x13, 0xF0, 0x32, 0xBB, + 0x01, 0x20, 0x12, 0xF0, 0xD1, 0xBC, 0x10, 0xB5, 0x01, 0x46, 0x34, 0x22, + 0xFA, 0x48, 0x13, 0xF0, + 0xA1, 0xFF, 0x01, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0x20, 0xFD, 0xF7, + 0x62, 0xB9, 0x30, 0xB5, + 0x85, 0xB0, 0x04, 0x46, 0x68, 0x46, 0x13, 0xF0, 0xB5, 0xFB, 0xF4, 0x48, + 0x00, 0x90, 0xAC, 0xB1, + 0x01, 0x2C, 0x15, 0xD0, 0x02, 0x2C, 0x15, 0xD0, 0x03, 0x2C, 0x31, 0xD1, + 0x5F, 0xF0, 0x08, 0x00, + 0x8D, 0xF8, 0x04, 0x00, 0x01, 0x20, 0x8D, 0xF8, 0x0D, 0x00, 0xED, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0xB0, 0x00, 0xC0, 0xF3, 0xC1, 0x00, 0x02, 0x28, 0x08, 0xD0, 0x0A, 0xE0, + 0x05, 0x20, 0xEF, 0xE7, + 0x06, 0x20, 0xED, 0xE7, 0x02, 0x20, 0x8D, 0xF8, 0x09, 0x00, 0xEB, 0xE7, + 0x00, 0x20, 0x8D, 0xF8, + 0x0D, 0x00, 0xE1, 0x4D, 0x03, 0x24, 0x68, 0x46, 0x13, 0xF0, 0xB1, 0xFB, + 0x00, 0x22, 0x04, 0xAB, + 0x01, 0x21, 0x10, 0x46, 0xFD, 0xF7, 0x76, 0xF9, 0x01, 0x21, 0x00, 0x20, + 0xFD, 0xF7, 0x55, 0xF9, + 0x28, 0x78, 0x00, 0x28, 0x04, 0xD0, 0x0F, 0xF0, 0x38, 0xF9, 0x64, 0x1E, + 0x00, 0x2C, 0xEA, 0xDC, + 0x05, 0xB0, 0x30, 0xBD, 0x2D, 0xE9, 0xF1, 0x4F, 0x88, 0xB0, 0x13, 0xF0, + 0xD0, 0xFB, 0x01, 0x90, + 0x13, 0xF0, 0xCF, 0xFB, 0x06, 0x46, 0xD2, 0x4C, 0x08, 0x98, 0x88, 0x46, + 0x00, 0x28, 0x20, 0x68, + 0x07, 0xD0, 0xB0, 0xF8, 0x7A, 0x11, 0x08, 0x98, 0xFF, 0xF7, 0x8E, 0xFF, + 0x03, 0x90, 0xCD, 0x48, + 0x10, 0xE0, 0x90, 0xF8, 0xE7, 0x00, 0x10, 0xF0, 0x60, 0x0F, 0x03, 0xD0, + 0x01, 0x98, 0x10, 0xF0, + 0xDB, 0xF8, 0x01, 0x90, 0x20, 0x68, 0xB0, 0xF8, 0x72, 0x11, 0x08, 0x98, + 0xFF, 0xF7, 0x7C, 0xFF, + 0x03, 0x90, 0xC5, 0x48, 0x02, 0x90, 0x20, 0x20, 0x06, 0x90, 0xBF, 0x48, + 0x4F, 0xF0, 0x40, 0x0A, + 0xB8, 0x21, 0xD0, 0x38, 0x13, 0xF0, 0x82, 0xFF, 0x00, 0x20, 0x00, 0x90, + 0x08, 0x98, 0xFF, 0xF7, + 0x86, 0xFF, 0xB9, 0x48, 0x00, 0x27, 0xB9, 0x46, 0x80, 0x68, 0x4F, 0xF0, + 0x01, 0x0B, 0x3C, 0x46, + 0x05, 0x90, 0x01, 0x20, 0x01, 0x99, 0xA0, 0x40, 0x08, 0x42, 0x40, 0xD0, + 0x00, 0x25, 0x2A, 0x46, + 0x01, 0x20, 0x00, 0x21, 0x13, 0xF0, 0x92, 0xFE, 0x02, 0x46, 0x0B, 0x46, + 0x30, 0x40, 0x01, 0xEA, + 0x08, 0x01, 0x08, 0x43, 0x21, 0xD0, 0xAC, 0x48, 0xD0, 0x38, 0x00, 0xEB, + 0xC4, 0x01, 0x04, 0x91, + 0xD1, 0xE9, 0x00, 0x01, 0x8E, 0x46, 0x00, 0xEA, 0x02, 0x0C, 0x19, 0x40, + 0x5C, 0xEA, 0x01, 0x0C, + 0x12, 0xD1, 0x05, 0x99, 0x31, 0xF9, 0x17, 0xC0, 0x03, 0x99, 0x8C, 0x45, + 0x06, 0xDC, 0x10, 0x43, + 0x04, 0x9A, 0x4E, 0xEA, 0x03, 0x01, 0xC2, 0xE9, 0x00, 0x01, 0x05, 0xE0, + 0x2A, 0x46, 0x49, 0x46, + 0x00, 0x9B, 0x02, 0x98, 0xFD, 0xF7, 0xF9, 0xFA, 0x7F, 0x1C, 0x6D, 0x1C, + 0x55, 0x45, 0xCE, 0xDB, + 0x99, 0x48, 0xD0, 0x38, 0x00, 0xEB, 0xC4, 0x01, 0xD1, 0xE9, 0x00, 0x01, + 0x70, 0x40, 0x81, 0xEA, + 0x08, 0x01, 0x08, 0x43, 0x01, 0xD0, 0x4F, 0xF0, 0x00, 0x0B, 0x09, 0xF1, + 0x01, 0x09, 0x06, 0x98, + 0x64, 0x1C, 0x84, 0x42, 0xB5, 0xDB, 0xBB, 0xF1, 0x01, 0x0F, 0x04, 0xD0, + 0x00, 0x98, 0x40, 0x1C, + 0x00, 0x90, 0x7F, 0x28, 0xA2, 0xDD, 0x09, 0xB0, 0x58, 0x46, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, + 0xF1, 0x4F, 0x8A, 0xB0, 0x13, 0xF0, 0x3B, 0xFB, 0x06, 0x90, 0x13, 0xF0, + 0x38, 0xFB, 0x00, 0x21, + 0xCD, 0xE9, 0x02, 0x01, 0x0A, 0x98, 0x86, 0x4C, 0x00, 0x28, 0x56, 0xD0, + 0x20, 0x68, 0xB0, 0xF8, + 0x7A, 0x11, 0x0A, 0x98, 0xFF, 0xF7, 0xF8, 0xFE, 0x01, 0x90, 0x82, 0x48, + 0x05, 0x90, 0x20, 0x20, + 0x09, 0x90, 0x4F, 0xF0, 0x40, 0x0A, 0x04, 0x21, 0x06, 0xA8, 0xFD, 0xF7, + 0xB4, 0xFE, 0x04, 0x46, + 0x08, 0x21, 0x02, 0xA8, 0xFD, 0xF7, 0xAF, 0xFE, 0x44, 0x43, 0x7C, 0x48, + 0x00, 0x90, 0x00, 0xF5, + 0xE6, 0x60, 0x21, 0x46, 0x04, 0x90, 0x13, 0xF0, 0xCF, 0xFE, 0x61, 0x00, + 0x00, 0x98, 0x13, 0xF0, + 0xCB, 0xFE, 0x71, 0x48, 0xB8, 0x21, 0xD0, 0x38, 0x13, 0xF0, 0xE8, 0xFE, + 0x00, 0x25, 0x0A, 0x98, + 0xFF, 0xF7, 0xED, 0xFE, 0x6C, 0x48, 0x4F, 0xF0, 0x00, 0x09, 0x4C, 0x46, + 0x80, 0x68, 0x07, 0x90, + 0x68, 0x42, 0x4F, 0xF0, 0x01, 0x0B, 0x4E, 0x46, 0x08, 0x90, 0x01, 0x20, + 0x06, 0x99, 0xB0, 0x40, + 0x08, 0x42, 0x79, 0xD0, 0x00, 0x27, 0x3A, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x13, 0xF0, 0xF6, 0xFD, + 0xDD, 0xE9, 0x02, 0x8C, 0x02, 0x46, 0x0B, 0x46, 0x00, 0xEA, 0x08, 0x00, + 0x01, 0xEA, 0x0C, 0x01, + 0x08, 0x43, 0x6A, 0xD0, 0x5C, 0x48, 0xD0, 0x38, 0x00, 0xEB, 0xC6, 0x0C, + 0xDC, 0xE9, 0x00, 0x01, + 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x0D, 0xD0, 0x89, 0xE0, 0x06, 0x98, + 0x0F, 0xF0, 0xFC, 0xFF, + 0x06, 0x90, 0x20, 0x68, 0xB0, 0xF8, 0x72, 0x11, 0x0A, 0x98, 0xFF, 0xF7, + 0x9D, 0xFE, 0x01, 0x90, + 0x55, 0x48, 0xA3, 0xE7, 0x00, 0x2D, 0x0A, 0xDA, 0x07, 0x98, 0x30, 0xF9, + 0x14, 0x10, 0x01, 0x98, + 0x81, 0x42, 0x01, 0xDB, 0x00, 0x21, 0x00, 0xE0, 0x01, 0x21, 0x04, 0x98, + 0x01, 0x55, 0x07, 0x98, + 0x01, 0x99, 0x30, 0xF9, 0x14, 0x00, 0x88, 0x42, 0x2A, 0xDD, 0x04, 0x99, + 0x09, 0x5D, 0x11, 0xB1, + 0x01, 0x29, 0x07, 0xD0, 0x63, 0xE0, 0x7F, 0x2D, 0x61, 0xDA, 0x00, 0x99, + 0x6B, 0x1C, 0x21, 0xF8, + 0x14, 0x00, 0x4C, 0xE0, 0xDC, 0xE9, 0x00, 0x10, 0x11, 0x43, 0x18, 0x43, + 0xCC, 0xE9, 0x00, 0x10, + 0x00, 0x98, 0x30, 0xF9, 0x14, 0x10, 0x01, 0x98, 0x08, 0x1A, 0x07, 0x99, + 0x31, 0xF9, 0x14, 0x20, + 0x01, 0x99, 0xA2, 0xEB, 0x01, 0x01, 0x00, 0xD5, 0x40, 0x42, 0x00, 0x29, + 0x00, 0xDA, 0x49, 0x42, + 0x88, 0x42, 0x3A, 0xDC, 0x08, 0x9B, 0x3A, 0x46, 0x49, 0x46, 0x5B, 0x1C, + 0x05, 0x98, 0x31, 0xE0, + 0x37, 0xDA, 0x04, 0x99, 0x09, 0x5D, 0x01, 0x29, 0x01, 0xD0, 0x79, 0xB1, + 0x37, 0xE0, 0x08, 0x99, + 0x11, 0xF1, 0x7F, 0x0F, 0x33, 0xDD, 0x00, 0x99, 0x3A, 0x46, 0x21, 0xF8, + 0x14, 0x00, 0x08, 0x9B, + 0x49, 0x46, 0x5B, 0x1E, 0x05, 0x98, 0x1D, 0xE0, 0x3E, 0xE0, 0x29, 0xE0, + 0xDC, 0xE9, 0x00, 0x10, + 0x11, 0x43, 0x18, 0x43, 0xCC, 0xE9, 0x00, 0x10, 0x00, 0x98, 0x30, 0xF9, + 0x14, 0x10, 0x01, 0x98, + 0x08, 0x1A, 0x07, 0x99, 0x31, 0xF9, 0x14, 0x20, 0x01, 0x99, 0xA2, 0xEB, + 0x01, 0x01, 0x00, 0xD5, + 0x40, 0x42, 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0x88, 0x42, 0x06, 0xDC, + 0x6B, 0x1E, 0x3A, 0x46, + 0x49, 0x46, 0x05, 0x98, 0xFD, 0xF7, 0xF1, 0xF9, 0x09, 0xE0, 0x00, 0x98, + 0x20, 0xF8, 0x14, 0x20, + 0x05, 0xE0, 0xDC, 0xE9, 0x00, 0x10, 0x11, 0x43, 0x18, 0x43, 0xCC, 0xE9, + 0x00, 0x10, 0x64, 0x1C, + 0x7F, 0x1C, 0x57, 0x45, 0xFF, 0xF6, 0x57, 0xAF, 0x0F, 0x48, 0xD0, 0x38, + 0x00, 0xEB, 0xC6, 0x01, + 0xD1, 0xE9, 0x00, 0x01, 0xDD, 0xE9, 0x02, 0x23, 0x50, 0x40, 0x59, 0x40, + 0x08, 0x43, 0x01, 0xD0, + 0x4F, 0xF0, 0x00, 0x0B, 0x09, 0xF1, 0x01, 0x09, 0x09, 0x98, 0x76, 0x1C, + 0x86, 0x42, 0xFF, 0xF6, + 0x3C, 0xAF, 0x58, 0x46, 0xBB, 0xF1, 0x01, 0x0F, 0x03, 0xD0, 0x6D, 0x1C, + 0x7F, 0x2D, 0x7F, 0xF7, + 0x26, 0xAF, 0x0B, 0xB0, 0xE9, 0xE6, 0x00, 0x00, 0x80, 0x10, 0x10, 0x00, + 0x47, 0x32, 0x00, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x08, 0x92, 0x01, 0x20, 0x78, 0x8B, 0x01, 0x20, + 0xD4, 0x56, 0x10, 0x00, + 0x2D, 0xE9, 0xF1, 0x4F, 0x96, 0xB0, 0x4F, 0xF0, 0x00, 0x0A, 0x13, 0xF0, + 0x18, 0xFA, 0x0D, 0x90, + 0x13, 0xF0, 0x17, 0xFA, 0xCD, 0xE9, 0x0E, 0x01, 0x16, 0x98, 0x48, 0xB1, + 0xFE, 0x48, 0x00, 0x68, + 0xB0, 0xF8, 0x7A, 0x11, 0x16, 0x98, 0xFF, 0xF7, 0xD7, 0xFD, 0x11, 0x90, + 0xFB, 0x48, 0x12, 0xE0, + 0xF9, 0x4C, 0x20, 0x68, 0x90, 0xF8, 0xE7, 0x00, 0x10, 0xF0, 0x60, 0x0F, + 0x03, 0xD0, 0x0D, 0x98, + 0x0F, 0xF0, 0x22, 0xFF, 0x0D, 0x90, 0x20, 0x68, 0xB0, 0xF8, 0x72, 0x11, + 0x16, 0x98, 0xFF, 0xF7, + 0xC3, 0xFD, 0x11, 0x90, 0xF2, 0x48, 0x01, 0x90, 0x40, 0x20, 0x0A, 0x90, + 0x20, 0x26, 0x04, 0x21, + 0x0D, 0xA8, 0xFD, 0xF7, 0x80, 0xFD, 0x0C, 0x90, 0x08, 0x21, 0x0E, 0xA8, + 0xFD, 0xF7, 0x7B, 0xFD, + 0x07, 0x90, 0xB8, 0x21, 0xEB, 0x48, 0x13, 0xF0, 0xC1, 0xFD, 0x01, 0x20, + 0x10, 0x90, 0x00, 0x20, + 0x04, 0x46, 0x05, 0x90, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x13, 0xF0, + 0xDF, 0xFC, 0xDD, 0xE9, + 0x0E, 0x23, 0x81, 0x46, 0x8B, 0x46, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, + 0x78, 0xD0, 0xDE, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x70, 0x01, 0x40, 0x07, 0x13, 0xD5, 0x05, 0x98, + 0x80, 0xB1, 0x00, 0x25, + 0x0B, 0xE0, 0xDD, 0xE9, 0x01, 0x02, 0x29, 0x46, 0xFD, 0xF7, 0x4C, 0xF9, + 0x03, 0x46, 0x22, 0x46, + 0x29, 0x46, 0x01, 0x98, 0xFD, 0xF7, 0x51, 0xF9, 0x6D, 0x1C, 0x0C, 0x98, + 0x85, 0x42, 0xF0, 0xDB, + 0x02, 0x94, 0x16, 0x98, 0xFF, 0xF7, 0x9B, 0xFD, 0xD2, 0x48, 0x4F, 0xF0, + 0x01, 0x08, 0xD0, 0x30, + 0x00, 0x25, 0x80, 0x68, 0x2F, 0x46, 0x14, 0x90, 0x01, 0x20, 0x0D, 0x99, + 0xB8, 0x40, 0x08, 0x42, + 0x45, 0xD0, 0xCC, 0x48, 0x00, 0xEB, 0xC7, 0x01, 0x15, 0x91, 0xD1, 0xE9, + 0x00, 0x01, 0x00, 0xEA, + 0x09, 0x00, 0x01, 0xEA, 0x0B, 0x01, 0x08, 0x43, 0x2E, 0xD1, 0x22, 0x46, + 0x29, 0x46, 0x01, 0x98, + 0xFD, 0xF7, 0x20, 0xF9, 0x07, 0x9A, 0x05, 0x99, 0x05, 0xFB, 0x02, 0x12, + 0x14, 0x99, 0x31, 0xF9, + 0x12, 0x20, 0x11, 0x99, 0x8A, 0x42, 0x0A, 0xDA, 0x15, 0x98, 0x15, 0x99, + 0xD0, 0xE9, 0x00, 0x20, + 0x42, 0xEA, 0x09, 0x02, 0x40, 0xEA, 0x0B, 0x00, 0xC1, 0xE9, 0x00, 0x20, + 0x14, 0xE0, 0x7F, 0x28, + 0x06, 0xDA, 0x43, 0x1C, 0x22, 0x46, 0x29, 0x46, 0x01, 0x98, 0xFD, 0xF7, + 0x0E, 0xF9, 0x0B, 0xE0, + 0x15, 0x98, 0x15, 0x9A, 0xD0, 0xE9, 0x00, 0x10, 0x41, 0xEA, 0x09, 0x01, + 0x40, 0xEA, 0x0B, 0x00, + 0xC2, 0xE9, 0x00, 0x10, 0x00, 0x20, 0x10, 0x90, 0x15, 0x99, 0x6D, 0x1C, + 0xD1, 0xE9, 0x00, 0x01, + 0x00, 0xEA, 0x09, 0x00, 0x01, 0xEA, 0x0B, 0x01, 0x08, 0x43, 0x00, 0xD1, + 0x80, 0x46, 0x7F, 0x1C, + 0xB7, 0x42, 0xB1, 0xDB, 0xB8, 0xF1, 0x00, 0x0F, 0xA3, 0xD0, 0x05, 0x98, + 0x40, 0x1C, 0x05, 0x90, + 0x0A, 0x98, 0x64, 0x1C, 0x84, 0x42, 0xFF, 0xF6, 0x75, 0xAF, 0x00, 0x20, + 0xB4, 0xE0, 0x00, 0xBF, + 0x4F, 0xF0, 0x00, 0x08, 0x45, 0x46, 0x2A, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x13, 0xF0, 0x4E, 0xFC, + 0xDD, 0xE9, 0x0E, 0x23, 0x83, 0x46, 0x06, 0x91, 0x10, 0x40, 0x19, 0x40, + 0x08, 0x43, 0x6E, 0xD0, + 0xB8, 0xF1, 0x00, 0x0F, 0x01, 0xD1, 0x4F, 0xF0, 0x01, 0x0A, 0x16, 0x98, + 0xFF, 0xF7, 0x1F, 0xFD, + 0x94, 0x48, 0x4F, 0xF0, 0x01, 0x09, 0xD0, 0x30, 0x00, 0x27, 0x80, 0x68, + 0x3C, 0x46, 0x14, 0x90, + 0x01, 0x20, 0x0D, 0x99, 0xA0, 0x40, 0x08, 0x42, 0x78, 0xD0, 0xB8, 0xF1, + 0x00, 0x0F, 0x0E, 0xDD, + 0x2A, 0x46, 0x39, 0x46, 0x01, 0x98, 0xFD, 0xF7, 0xAD, 0xF8, 0x8A, 0x49, + 0x2A, 0x46, 0xB8, 0x31, + 0x09, 0x57, 0x0B, 0x18, 0x39, 0x46, 0x01, 0x98, 0xFD, 0xF7, 0xAF, 0xF8, + 0x65, 0xE0, 0xBA, 0xF1, + 0x01, 0x0F, 0x12, 0xD1, 0x2A, 0x46, 0x39, 0x46, 0x01, 0x98, 0xFD, 0xF7, + 0x9B, 0xF8, 0x81, 0x49, + 0xB8, 0x31, 0x08, 0x55, 0x7F, 0x48, 0x00, 0xEB, 0xC4, 0x03, 0xD3, 0xE9, + 0x00, 0x01, 0x06, 0x9A, + 0x20, 0xEA, 0x0B, 0x00, 0x91, 0x43, 0xC3, 0xE9, 0x00, 0x01, 0x7A, 0x48, + 0x06, 0x9B, 0x00, 0xEB, + 0xC4, 0x00, 0x0C, 0x90, 0xD0, 0xE9, 0x00, 0x10, 0x01, 0xEA, 0x0B, 0x01, + 0x18, 0x40, 0x01, 0x43, + 0x39, 0xD1, 0x2A, 0x46, 0x39, 0x46, 0x01, 0x98, 0xFD, 0xF7, 0x7C, 0xF8, + 0x07, 0x9A, 0x14, 0x99, + 0x07, 0xFB, 0x02, 0x82, 0x31, 0xF9, 0x12, 0x20, 0x11, 0x99, 0x8A, 0x42, + 0x0E, 0xDA, 0x0C, 0x99, + 0x06, 0x9B, 0xD1, 0xE9, 0x00, 0xC2, 0x4C, 0xEA, 0x0B, 0x0C, 0x1A, 0x43, + 0xC1, 0xE9, 0x00, 0xC2, + 0x68, 0x49, 0xB8, 0x31, 0x0A, 0x5D, 0x80, 0x1A, 0x08, 0x55, 0x1C, 0xE0, + 0x7F, 0x28, 0x07, 0xDA, + 0x43, 0x1C, 0x2A, 0x46, 0x39, 0x46, 0x01, 0x98, 0xFD, 0xF7, 0x67, 0xF8, + 0x13, 0xE0, 0x29, 0xE0, + 0x0C, 0x99, 0xDD, 0xF8, 0x18, 0xC0, 0x0C, 0x9B, 0xD1, 0xE9, 0x00, 0x21, + 0x42, 0xEA, 0x0B, 0x02, + 0x41, 0xEA, 0x0C, 0x01, 0xC3, 0xE9, 0x00, 0x21, 0x5A, 0x49, 0xB8, 0x31, + 0x0A, 0x5D, 0x80, 0x1A, + 0x08, 0x55, 0x00, 0x20, 0x10, 0x90, 0x0C, 0x98, 0x06, 0x9A, 0xD0, 0xE9, + 0x00, 0x10, 0x01, 0xEA, + 0x0B, 0x01, 0x10, 0x40, 0x01, 0x43, 0x00, 0xD1, 0x89, 0x46, 0x7F, 0x1C, + 0x64, 0x1C, 0xB4, 0x42, + 0xFF, 0xF6, 0x7E, 0xAF, 0x4F, 0xF0, 0x00, 0x0A, 0xB9, 0xF1, 0x00, 0x0F, + 0x3F, 0xF4, 0x6D, 0xAF, + 0x08, 0xF1, 0x01, 0x08, 0x0A, 0x98, 0x6D, 0x1C, 0x85, 0x42, 0xFF, 0xF6, + 0x54, 0xAF, 0x16, 0x98, + 0xFF, 0xF7, 0x85, 0xFC, 0x0B, 0x98, 0x40, 0x1C, 0x0B, 0x90, 0x43, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0x70, 0x11, 0x0B, 0x98, 0xB0, 0xEB, 0x11, 0x1F, 0xFF, 0xF6, 0x42, 0xAF, + 0x10, 0x98, 0x17, 0xB0, + 0x4B, 0xE5, 0x2D, 0xE9, 0xF0, 0x4F, 0x8B, 0xB0, 0x13, 0xF0, 0x8D, 0xF8, + 0x09, 0x90, 0x13, 0xF0, + 0x8C, 0xF8, 0x8A, 0x46, 0x38, 0x49, 0x81, 0x46, 0x00, 0x20, 0x0A, 0x68, + 0x01, 0x46, 0x16, 0x46, + 0x92, 0xF8, 0x61, 0x54, 0x01, 0x24, 0x02, 0xF2, 0x72, 0x42, 0x00, 0xBF, + 0x04, 0xFA, 0x01, 0xF3, + 0x1D, 0x42, 0x03, 0xD0, 0x57, 0x5C, 0x04, 0xFA, 0x07, 0xF3, 0x18, 0x43, + 0x49, 0x1C, 0x04, 0x29, + 0xF4, 0xDB, 0x01, 0x90, 0x00, 0x20, 0x00, 0x90, 0x20, 0x20, 0x08, 0x90, + 0x40, 0x20, 0x07, 0x90, + 0xB6, 0xF8, 0x82, 0x11, 0x02, 0x20, 0xFF, 0xF7, 0x2F, 0xFC, 0x03, 0x90, + 0x2A, 0x48, 0x05, 0x90, + 0x2A, 0x48, 0x00, 0x21, 0x02, 0x90, 0x01, 0x60, 0x0D, 0x46, 0x41, 0x60, + 0x02, 0x20, 0xFF, 0xF7, + 0x3E, 0xFC, 0x24, 0x48, 0x00, 0x24, 0xD0, 0x30, 0xA3, 0x46, 0x40, 0x69, + 0x06, 0x90, 0x01, 0x20, + 0x27, 0x46, 0x04, 0x90, 0x01, 0x20, 0x09, 0x99, 0xB8, 0x40, 0x08, 0x42, + 0x63, 0xD0, 0x00, 0x26, + 0x32, 0x46, 0x01, 0x20, 0x00, 0x21, 0x13, 0xF0, 0x49, 0xFB, 0x80, 0x46, + 0x0A, 0x46, 0x00, 0xEA, + 0x09, 0x00, 0x01, 0xEA, 0x0A, 0x01, 0x08, 0x43, 0x4F, 0xD0, 0x16, 0x48, + 0x00, 0xEB, 0xC7, 0x01, + 0xD1, 0xE9, 0x00, 0x01, 0x00, 0xEA, 0x08, 0x00, 0x11, 0x40, 0x08, 0x43, + 0x44, 0xD1, 0x01, 0x20, + 0x01, 0x99, 0x00, 0xFA, 0x04, 0xF8, 0x18, 0xEA, 0x01, 0x0F, 0x3D, 0xD0, + 0x06, 0x98, 0x30, 0xF9, + 0x14, 0x20, 0x03, 0x98, 0x82, 0x42, 0x2C, 0xDC, 0x00, 0x2D, 0x2A, 0xDD, + 0x02, 0x98, 0x30, 0xF9, + 0x14, 0x10, 0x03, 0x98, 0x08, 0x1A, 0x03, 0x99, 0xA2, 0xEB, 0x01, 0x01, + 0x00, 0xD5, 0x40, 0x42, + 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0x0B, 0xE0, 0x4C, 0x07, 0x10, 0x00, + 0x08, 0x92, 0x01, 0x20, + 0x78, 0x8B, 0x01, 0x20, 0xB0, 0x0F, 0x10, 0x00, 0x98, 0x98, 0x01, 0x20, + 0xD4, 0x56, 0x10, 0x00, + 0x88, 0x42, 0x06, 0xDC, 0x6B, 0x1E, 0x32, 0x46, 0x59, 0x46, 0x05, 0x98, + 0xFC, 0xF7, 0x95, 0xFF, + 0x02, 0xE0, 0x02, 0x98, 0x20, 0xF8, 0x14, 0x20, 0x00, 0x99, 0x48, 0xEA, + 0x01, 0x00, 0x00, 0x90, + 0x0A, 0xE0, 0x7F, 0x2D, 0x08, 0xDA, 0x02, 0x98, 0x6B, 0x1C, 0x59, 0x46, + 0x20, 0xF8, 0x14, 0x20, + 0x32, 0x46, 0x05, 0x98, 0xFC, 0xF7, 0x81, 0xFF, 0x64, 0x1C, 0x07, 0x98, + 0x76, 0x1C, 0x86, 0x42, + 0x9E, 0xDB, 0x0B, 0xF1, 0x01, 0x0B, 0x08, 0x98, 0x7F, 0x1C, 0x87, 0x42, + 0x92, 0xDB, 0xDD, 0xE9, + 0x00, 0x01, 0x88, 0x42, 0x05, 0xD0, 0x00, 0x20, 0x6D, 0x1C, 0x04, 0x90, + 0x7F, 0x2D, 0x7F, 0xF7, + 0x7D, 0xAF, 0x04, 0x98, 0xA5, 0xE5, 0x2D, 0xE9, 0xFF, 0x5F, 0x04, 0x46, + 0x01, 0x25, 0x12, 0xF0, + 0xD0, 0xFF, 0xCD, 0xE9, 0x02, 0x01, 0xC5, 0x48, 0x40, 0x27, 0x08, 0x21, + 0x00, 0x68, 0x00, 0xF2, + 0x02, 0x60, 0x01, 0x90, 0xC2, 0x48, 0x00, 0x90, 0x02, 0xA8, 0xFD, 0xF7, + 0x54, 0xFB, 0x06, 0x46, + 0x01, 0x2C, 0x6E, 0xD1, 0xDD, 0xE9, 0x02, 0x23, 0x29, 0x46, 0x00, 0x98, + 0xFC, 0xF7, 0x5C, 0xFF, + 0xDF, 0xF8, 0xF0, 0x92, 0x00, 0x20, 0x09, 0xEB, 0x46, 0x0B, 0x47, 0xF6, + 0xFF, 0x72, 0x6F, 0xF0, + 0x7E, 0x01, 0x04, 0xE0, 0x29, 0xF8, 0x10, 0x20, 0x0B, 0xF8, 0x00, 0x10, + 0x40, 0x1C, 0xB0, 0x42, + 0xF8, 0xDB, 0x6F, 0xF0, 0x7F, 0x08, 0x03, 0x20, 0xFF, 0xF7, 0x89, 0xFB, + 0xB2, 0x48, 0x00, 0x24, + 0x25, 0x46, 0xD0, 0xF8, 0x08, 0xA0, 0x2A, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x13, 0xF0, 0x9E, 0xFA, + 0xDD, 0xE9, 0x02, 0x23, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x1D, 0xD0, + 0x3A, 0xF9, 0x14, 0x10, + 0x39, 0xF9, 0x14, 0x00, 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0x00, 0x28, + 0x00, 0xDA, 0x40, 0x42, + 0x81, 0x42, 0x0A, 0xDA, 0x2A, 0x46, 0x00, 0x21, 0x00, 0x98, 0xFC, 0xF7, + 0x0B, 0xFF, 0x0B, 0xF8, + 0x04, 0x00, 0x3A, 0xF8, 0x14, 0x10, 0x29, 0xF8, 0x14, 0x10, 0x43, 0x46, + 0x2A, 0x46, 0x00, 0x21, + 0x00, 0x98, 0xFC, 0xF7, 0x0A, 0xFF, 0x64, 0x1C, 0x6D, 0x1C, 0xBD, 0x42, + 0xD3, 0xDB, 0x08, 0xF1, + 0x01, 0x08, 0xB8, 0xF1, 0x7F, 0x0F, 0xC6, 0xDD, 0x00, 0x25, 0x2C, 0x46, + 0x22, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x13, 0xF0, 0x6B, 0xFA, 0xDD, 0xE9, 0x02, 0x23, 0x10, 0x40, + 0x19, 0x40, 0x08, 0x43, + 0x07, 0xD0, 0x1B, 0xF9, 0x05, 0x30, 0x22, 0x46, 0x00, 0x21, 0x00, 0x98, + 0xFC, 0xF7, 0xED, 0xFE, + 0x6D, 0x1C, 0x64, 0x1C, 0xBC, 0x42, 0xE9, 0xDB, 0xDD, 0xE9, 0x00, 0x10, + 0x26, 0x22, 0x13, 0xF0, + 0x8C, 0xFA, 0x00, 0x25, 0xDF, 0xF8, 0x24, 0x82, 0x2C, 0x46, 0x22, 0x46, + 0x01, 0x20, 0x00, 0x21, + 0x13, 0xF0, 0x4C, 0xFA, 0xDD, 0xE9, 0x02, 0x23, 0x10, 0x40, 0x19, 0x40, + 0x08, 0x43, 0x07, 0xD0, + 0x22, 0x46, 0x00, 0x21, 0x00, 0x98, 0xFC, 0xF7, 0xC5, 0xFE, 0x28, 0xF8, + 0x15, 0x00, 0x6D, 0x1C, + 0x64, 0x1C, 0xBC, 0x42, 0xE9, 0xDB, 0x03, 0x20, 0xFF, 0xF7, 0x19, 0xFB, + 0x7A, 0x48, 0x42, 0x46, + 0x81, 0x68, 0x00, 0x20, 0x06, 0xE0, 0x00, 0xBF, 0x31, 0xF8, 0x10, 0x30, + 0x34, 0x18, 0x40, 0x1C, + 0x22, 0xF8, 0x14, 0x30, 0xB0, 0x42, 0xF7, 0xDB, 0xBD, 0xE8, 0xFF, 0x9F, + 0x2D, 0xE9, 0xF0, 0x5F, + 0x07, 0x46, 0x01, 0x24, 0x00, 0x20, 0xFC, 0xF7, 0x44, 0xFD, 0x02, 0x20, + 0xFC, 0xF7, 0x41, 0xFD, + 0x6F, 0x49, 0x01, 0x20, 0x08, 0x70, 0x69, 0x4E, 0xF8, 0x07, 0x4F, 0xF0, + 0x00, 0x08, 0x4F, 0xF0, + 0xA5, 0x09, 0x09, 0xD0, 0x00, 0xF0, 0x55, 0xF8, 0x10, 0xF0, 0x01, 0x04, + 0x04, 0xD0, 0x30, 0x68, + 0x80, 0xF8, 0x1B, 0x80, 0x80, 0xF8, 0x1A, 0x90, 0xB8, 0x07, 0x09, 0xD5, + 0x00, 0xF0, 0x8F, 0xF8, + 0x20, 0x40, 0x04, 0x00, 0x04, 0xD0, 0x30, 0x68, 0x80, 0xF8, 0x1D, 0x80, + 0x80, 0xF8, 0x1C, 0x90, + 0xDF, 0xF8, 0x80, 0xA1, 0xDA, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x61, 0x04, + 0x58, 0xB3, 0xF8, 0x06, + 0x29, 0xD5, 0x01, 0x25, 0x12, 0xF0, 0xEF, 0xFE, 0x83, 0x46, 0x12, 0xF0, + 0xEE, 0xFE, 0xDA, 0xF8, + 0x00, 0x20, 0x92, 0xF8, 0x80, 0x21, 0xD2, 0x07, 0x13, 0xD0, 0x02, 0x46, + 0x0B, 0x46, 0x59, 0x46, + 0x55, 0x48, 0xFC, 0xF7, 0x81, 0xFE, 0xDA, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0x80, 0x01, 0xC0, 0x07, + 0x07, 0xD0, 0xFF, 0xF7, 0x46, 0xFE, 0x05, 0x00, 0x03, 0xD1, 0x02, 0x21, + 0x74, 0x20, 0x0E, 0xF0, + 0x1D, 0xFC, 0x02, 0x20, 0xFF, 0xF7, 0xB3, 0xFA, 0x2C, 0x40, 0x04, 0xD0, + 0x30, 0x68, 0x80, 0xF8, + 0x25, 0x80, 0x80, 0xF8, 0x24, 0x90, 0x00, 0x20, 0xFC, 0xF7, 0x06, 0xFD, + 0x02, 0x20, 0xFC, 0xF7, + 0x03, 0xFD, 0xF8, 0x07, 0x02, 0xD0, 0x01, 0x20, 0x00, 0xF0, 0xBA, 0xF8, + 0x20, 0x46, 0xBD, 0xE8, + 0xF0, 0x9F, 0x2D, 0xE9, 0xF0, 0x41, 0x01, 0x24, 0x12, 0xF0, 0xB1, 0xFE, + 0x80, 0x46, 0x12, 0xF0, + 0xB0, 0xFE, 0x3C, 0x4D, 0x06, 0x46, 0x0F, 0x46, 0x28, 0x68, 0x90, 0xF8, + 0xE7, 0x00, 0x10, 0xF0, + 0x60, 0x0F, 0x03, 0xD0, 0x40, 0x46, 0x0F, 0xF0, 0xC7, 0xFB, 0x80, 0x46, + 0x28, 0x68, 0x90, 0xF8, + 0x70, 0x01, 0xC0, 0x07, 0x25, 0xD0, 0x32, 0x46, 0x3B, 0x46, 0x41, 0x46, + 0x33, 0x48, 0xFC, 0xF7, + 0x3B, 0xFE, 0x28, 0x68, 0x90, 0xF8, 0x70, 0x11, 0xC9, 0x07, 0x1A, 0xD0, + 0x90, 0xF8, 0xE8, 0x10, + 0x89, 0x07, 0x03, 0xD4, 0x00, 0x20, 0xFF, 0xF7, 0x6B, 0xFC, 0x0C, 0xE0, + 0x90, 0xF8, 0xE7, 0x00, + 0xC0, 0xF3, 0x41, 0x10, 0x02, 0x28, 0x4F, 0xF0, 0x00, 0x00, 0x02, 0xD3, + 0xFF, 0xF7, 0x3F, 0xFB, + 0x01, 0xE0, 0xFF, 0xF7, 0xA7, 0xFA, 0x04, 0x00, 0x03, 0xD1, 0x01, 0x21, + 0x74, 0x20, 0x0E, 0xF0, + 0xC5, 0xFB, 0x00, 0x20, 0xFF, 0xF7, 0x5B, 0xFA, 0x20, 0x46, 0xBD, 0xE8, + 0xF0, 0x81, 0x70, 0xB5, + 0x01, 0x24, 0x12, 0xF0, 0x6C, 0xFE, 0x06, 0x46, 0x12, 0xF0, 0x6B, 0xFE, + 0x19, 0x4D, 0x2A, 0x68, + 0x92, 0xF8, 0x78, 0x21, 0xD2, 0x07, 0x1B, 0xD0, 0x02, 0x46, 0x0B, 0x46, + 0x31, 0x46, 0x18, 0x48, + 0xFC, 0xF7, 0x02, 0xFE, 0x28, 0x68, 0x90, 0xF8, 0x78, 0x11, 0xC9, 0x07, + 0x10, 0xD0, 0x90, 0xF8, + 0xE8, 0x00, 0x80, 0x07, 0x20, 0x46, 0x02, 0xD4, 0xFF, 0xF7, 0x32, 0xFC, + 0x01, 0xE0, 0xFF, 0xF7, + 0x79, 0xFA, 0x04, 0x00, 0x04, 0xD1, 0x4F, 0xF4, 0x80, 0x71, 0x74, 0x20, + 0x0E, 0xF0, 0x96, 0xFB, + 0x01, 0x20, 0xFF, 0xF7, 0x2C, 0xFA, 0x20, 0x46, 0x70, 0xBD, 0x00, 0x00, + 0x50, 0x07, 0x10, 0x00, + 0xE4, 0x9F, 0x01, 0x20, 0xD4, 0x56, 0x10, 0x00, 0x80, 0x10, 0x10, 0x00, + 0x04, 0x4B, 0x01, 0x20, + 0x78, 0x07, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x98, 0x98, 0x01, 0x20, + 0x78, 0x8B, 0x01, 0x20, + 0x08, 0x92, 0x01, 0x20, 0x10, 0xB5, 0xFF, 0xF7, 0xD6, 0xF9, 0x53, 0x20, + 0xFF, 0xF7, 0x06, 0xFF, + 0x00, 0x28, 0x12, 0xD0, 0x4F, 0xF4, 0xD6, 0x70, 0x00, 0xF0, 0x7B, 0xFF, + 0x00, 0x28, 0x0C, 0xD0, + 0x24, 0x48, 0x25, 0x49, 0x00, 0x68, 0x09, 0x68, 0x90, 0xF8, 0xDE, 0x00, + 0x08, 0x76, 0xFE, 0xF7, + 0x45, 0xFE, 0xBD, 0xE8, 0x10, 0x40, 0xFE, 0xF7, 0xD5, 0xBD, 0x10, 0xBD, + 0x10, 0xB5, 0xFF, 0xF7, + 0xBA, 0xF9, 0x40, 0xF2, 0xFF, 0x10, 0xFE, 0xF7, 0x41, 0xFD, 0x1A, 0x48, + 0x1A, 0x49, 0x00, 0x68, + 0x09, 0x68, 0x90, 0xF8, 0xDE, 0x00, 0x08, 0x76, 0xBD, 0xE8, 0x10, 0x40, + 0xFE, 0xF7, 0xC2, 0xBD, + 0x2D, 0xE9, 0xF0, 0x41, 0x13, 0x49, 0x09, 0x68, 0x91, 0xF8, 0xC1, 0x21, + 0xD2, 0x07, 0x1F, 0xD0, + 0x01, 0x28, 0x1D, 0xD1, 0x10, 0x4F, 0x91, 0xF8, 0x31, 0x20, 0x91, 0xF8, + 0x30, 0x10, 0x3D, 0x68, + 0x4A, 0x43, 0x02, 0x20, 0x0D, 0x4E, 0x14, 0xB2, 0x32, 0x35, 0xFD, 0xF7, + 0xE2, 0xFF, 0x03, 0x20, + 0xFC, 0xF7, 0x0F, 0xFC, 0x38, 0x68, 0x62, 0x00, 0x31, 0x46, 0x04, 0x86, + 0x28, 0x46, 0x13, 0xF0, + 0x1C, 0xF9, 0x03, 0x20, 0xFC, 0xF7, 0x20, 0xFC, 0xBD, 0xE8, 0xF0, 0x41, + 0xFE, 0xF7, 0x9A, 0xBD, + 0xBD, 0xE8, 0xF0, 0x81, 0x4C, 0x07, 0x10, 0x00, 0x50, 0x07, 0x10, 0x00, + 0x42, 0x44, 0x01, 0x20, + 0x10, 0xB5, 0x01, 0x46, 0x34, 0x22, 0xFB, 0x48, 0x13, 0xF0, 0x4C, 0xF9, + 0x01, 0x21, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x20, 0xFC, 0xF7, 0x0D, 0xBB, 0x30, 0xB5, 0x85, 0xB0, + 0x68, 0x46, 0x12, 0xF0, + 0x61, 0xFD, 0xF5, 0x48, 0x02, 0x22, 0x00, 0x78, 0xE0, 0xB1, 0x03, 0x21, + 0x01, 0x28, 0x0D, 0xD0, + 0x03, 0x28, 0x0E, 0xD0, 0x02, 0x28, 0x18, 0xD0, 0x04, 0x22, 0x05, 0x28, + 0x0C, 0xD0, 0x04, 0x28, + 0x0D, 0xD0, 0x06, 0x28, 0x0E, 0xD0, 0x07, 0x28, 0x0F, 0xD0, 0x10, 0xE0, + 0x8D, 0xF8, 0x06, 0x10, + 0x0D, 0xE0, 0x8D, 0xF8, 0x08, 0x10, 0x0A, 0xE0, 0x8D, 0xF8, 0x0A, 0x20, + 0x07, 0xE0, 0x8D, 0xF8, + 0x0A, 0x10, 0x04, 0xE0, 0x8D, 0xF8, 0x06, 0x20, 0x01, 0xE0, 0x8D, 0xF8, + 0x08, 0x20, 0xE3, 0x48, + 0x00, 0x90, 0xE3, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xB0, 0x10, 0xC9, 0x07, + 0x0B, 0xD0, 0x01, 0x21, + 0x8D, 0xF8, 0x0D, 0x10, 0x90, 0xF8, 0xB0, 0x00, 0xC0, 0xF3, 0xC1, 0x00, + 0x02, 0x28, 0x02, 0xD1, + 0x00, 0x20, 0x8D, 0xF8, 0x0D, 0x00, 0xD7, 0x4D, 0x03, 0x24, 0x68, 0x46, + 0x12, 0xF0, 0x47, 0xFD, + 0x00, 0x22, 0x04, 0xAB, 0x01, 0x21, 0x10, 0x46, 0xFC, 0xF7, 0x0C, 0xFB, + 0x01, 0x21, 0x00, 0x20, + 0xFC, 0xF7, 0xEB, 0xFA, 0x28, 0x78, 0x00, 0x28, 0x04, 0xD0, 0x0E, 0xF0, + 0xCE, 0xFA, 0x64, 0x1E, + 0x00, 0x2C, 0xEA, 0xDC, 0x05, 0xB0, 0x30, 0xBD, 0x2D, 0xE9, 0xF0, 0x4F, + 0xCA, 0x4E, 0x04, 0x46, + 0x87, 0xB0, 0x06, 0x20, 0x89, 0x46, 0x30, 0x70, 0x12, 0xF0, 0x61, 0xFD, + 0x00, 0x21, 0x20, 0x27, + 0xCD, 0xE9, 0x04, 0x01, 0x1D, 0x20, 0xC7, 0x4D, 0x02, 0x90, 0x24, 0xB1, + 0x01, 0x2C, 0x0E, 0xD0, + 0x02, 0x2C, 0x21, 0xD0, 0x2F, 0xE0, 0xC4, 0x48, 0x00, 0x90, 0xDF, 0xF8, + 0xF8, 0x82, 0x28, 0x68, + 0x08, 0xF1, 0x18, 0x08, 0xDF, 0xF8, 0x04, 0xA3, 0x00, 0xF5, 0xC5, 0x60, + 0x22, 0xE0, 0x12, 0xF0, + 0x48, 0xFD, 0xCD, 0xE9, 0x04, 0x01, 0xBC, 0x48, 0x40, 0x27, 0x20, 0x30, + 0x00, 0x90, 0x28, 0x68, + 0xDF, 0xF8, 0xD0, 0x82, 0x00, 0xF2, 0x5E, 0x60, 0x01, 0x90, 0x26, 0x20, + 0x08, 0xF1, 0x1C, 0x08, + 0xDF, 0xF8, 0xDC, 0xA2, 0x02, 0x90, 0x0E, 0xE0, 0x07, 0x20, 0x30, 0x70, + 0xB2, 0x48, 0xDF, 0xF8, + 0xB4, 0x82, 0x48, 0x30, 0x00, 0x90, 0x28, 0x68, 0xDF, 0xF8, 0xC8, 0xA2, + 0x08, 0xF1, 0x28, 0x08, + 0x00, 0xF2, 0x84, 0x60, 0x01, 0x90, 0x08, 0x21, 0x04, 0xA8, 0xFD, 0xF7, + 0xB4, 0xF8, 0x04, 0x46, + 0xB9, 0xF1, 0x01, 0x0F, 0x74, 0xD1, 0x22, 0x46, 0x04, 0xA9, 0x00, 0x98, + 0xFC, 0xF7, 0xF7, 0xFC, + 0xDF, 0xF8, 0xA4, 0xB2, 0x47, 0xF6, 0xFF, 0x71, 0x0B, 0xEB, 0x44, 0x00, + 0x03, 0x90, 0x00, 0x20, + 0x6F, 0xF0, 0x7E, 0x02, 0x05, 0xE0, 0x00, 0xBF, 0x2B, 0xF8, 0x10, 0x10, + 0x03, 0x9B, 0x1A, 0x54, + 0x40, 0x1C, 0xA0, 0x42, 0xF8, 0xDB, 0x6F, 0xF0, 0x7F, 0x09, 0x00, 0xBF, + 0xFF, 0xF7, 0x3C, 0xFF, + 0xD8, 0xF8, 0x00, 0x00, 0x00, 0x25, 0x2E, 0x46, 0x06, 0x90, 0x2B, 0xE0, + 0x32, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x12, 0xF0, 0xFB, 0xFF, 0xDD, 0xE9, 0x04, 0x23, 0x10, 0x40, + 0x19, 0x40, 0x08, 0x43, + 0x1D, 0xD0, 0x06, 0x98, 0x30, 0xF9, 0x15, 0x10, 0x3B, 0xF9, 0x15, 0x00, + 0x00, 0x29, 0x00, 0xDA, + 0x49, 0x42, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, 0x81, 0x42, 0x0A, 0xDA, + 0x31, 0x46, 0x00, 0x98, + 0xFC, 0xF7, 0xAB, 0xFC, 0x03, 0x99, 0x48, 0x55, 0x06, 0x98, 0x30, 0xF8, + 0x15, 0x10, 0x2B, 0xF8, + 0x15, 0x10, 0x4A, 0x46, 0x31, 0x46, 0x00, 0x98, 0xFC, 0xF7, 0xA6, 0xFC, + 0x6D, 0x1C, 0xA5, 0x42, + 0x02, 0xD0, 0x76, 0x1C, 0xBE, 0x42, 0xD1, 0xDB, 0x09, 0xF1, 0x01, 0x09, + 0xB9, 0xF1, 0x7F, 0x0F, + 0xC4, 0xDD, 0x00, 0x26, 0x35, 0x46, 0x14, 0xE0, 0x2A, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x12, 0xF0, + 0xC5, 0xFF, 0xDD, 0xE9, 0x04, 0x23, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, + 0x06, 0xD0, 0x03, 0x98, + 0x29, 0x46, 0x82, 0x57, 0x00, 0x98, 0xFC, 0xF7, 0x87, 0xFC, 0x76, 0x1C, + 0xA6, 0x42, 0x02, 0xD0, + 0x6D, 0x1C, 0xBD, 0x42, 0xE8, 0xDB, 0xDD, 0xE9, 0x00, 0x10, 0x02, 0x9A, + 0x12, 0xF0, 0xE5, 0xFF, + 0x00, 0x26, 0x35, 0x46, 0x14, 0xE0, 0x2A, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x12, 0xF0, 0xA6, 0xFF, + 0xDD, 0xE9, 0x04, 0x23, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x06, 0xD0, + 0x29, 0x46, 0x00, 0x98, + 0xFC, 0xF7, 0x63, 0xFC, 0x2A, 0xF8, 0x16, 0x00, 0x76, 0x1C, 0xA6, 0x42, + 0x02, 0xD0, 0x6D, 0x1C, + 0xBD, 0x42, 0xE8, 0xDB, 0xFF, 0xF7, 0xC8, 0xFE, 0x00, 0x20, 0xD8, 0xF8, + 0x00, 0x10, 0x05, 0xE0, + 0x31, 0xF8, 0x10, 0x30, 0x25, 0x18, 0x40, 0x1C, 0x2A, 0xF8, 0x15, 0x30, + 0xA0, 0x42, 0xF7, 0xDB, + 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x70, 0xB5, 0x55, 0x4C, 0x05, 0x46, + 0x20, 0x68, 0x90, 0xF8, + 0x88, 0x01, 0xC0, 0x06, 0x07, 0xD5, 0x29, 0x46, 0x00, 0x20, 0xFF, 0xF7, + 0x05, 0xFF, 0x29, 0x46, + 0x01, 0x20, 0xFF, 0xF7, 0x01, 0xFF, 0x20, 0x68, 0x90, 0xF8, 0xA0, 0x01, + 0xC0, 0x06, 0x04, 0xD5, + 0x29, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x02, 0x20, 0xF6, 0xE6, 0x70, 0xBD, + 0x2D, 0xE9, 0xF0, 0x47, + 0x45, 0x49, 0x00, 0x25, 0x2C, 0x46, 0x0E, 0x69, 0xD1, 0xF8, 0x38, 0x30, + 0x28, 0x46, 0x01, 0x27, + 0x07, 0xFA, 0x00, 0xF2, 0x32, 0x42, 0x03, 0xD0, 0x1A, 0x5C, 0xAA, 0x42, + 0x00, 0xD9, 0x15, 0x46, + 0x40, 0x1C, 0x20, 0x28, 0xF4, 0xD3, 0xD1, 0xE9, 0x14, 0x78, 0xD1, 0xF8, + 0x3C, 0x90, 0x00, 0x26, + 0x8A, 0x46, 0x32, 0x46, 0x01, 0x20, 0x00, 0x21, 0x12, 0xF0, 0x48, 0xFF, + 0x38, 0x40, 0x01, 0xEA, + 0x08, 0x01, 0x08, 0x43, 0x04, 0xD0, 0x19, 0xF8, 0x06, 0x00, 0xA0, 0x42, + 0x00, 0xD9, 0x04, 0x46, + 0x76, 0x1C, 0x40, 0x2E, 0xED, 0xD3, 0xDA, 0xF8, 0x48, 0x20, 0x50, 0x46, + 0x15, 0x70, 0xDA, 0xF8, + 0x4C, 0x10, 0x0C, 0x70, 0xDA, 0xF8, 0x30, 0x30, 0xDA, 0xF8, 0x28, 0x70, + 0xDA, 0xF8, 0x34, 0x60, + 0x1B, 0x78, 0x3F, 0x78, 0x2B, 0x44, 0x3B, 0x44, 0xDA, 0xF8, 0x2C, 0x70, + 0x36, 0x78, 0x3F, 0x78, + 0x26, 0x44, 0x3E, 0x44, 0x07, 0x69, 0x6F, 0xB1, 0xD0, 0xE9, 0x14, 0x7C, + 0x57, 0xEA, 0x0C, 0x07, + 0x0A, 0xD0, 0xFF, 0x27, 0xB3, 0x42, 0x13, 0xD2, 0xF3, 0x1A, 0x2B, 0x44, + 0xFF, 0x2B, 0x07, 0xD8, + 0x13, 0x70, 0x0B, 0xE0, 0x14, 0x70, 0x09, 0xE0, 0x15, 0x70, 0x0D, 0x70, + 0xBD, 0xE8, 0xF0, 0x87, + 0x17, 0x70, 0xC2, 0x69, 0x42, 0xF4, 0x00, 0x72, 0xCA, 0xF8, 0x1C, 0x20, + 0x0C, 0x70, 0xF5, 0xE7, + 0x9E, 0x42, 0x0D, 0xD2, 0x9B, 0x1B, 0x23, 0x44, 0xFF, 0x2B, 0x01, 0xD8, + 0x0B, 0x70, 0x05, 0xE0, + 0x0F, 0x70, 0xC1, 0x69, 0x41, 0xF4, 0x00, 0x71, 0xCA, 0xF8, 0x1C, 0x10, + 0x15, 0x70, 0xE5, 0xE7, + 0x15, 0x70, 0xEB, 0xE7, 0x2D, 0xE9, 0xF0, 0x41, 0x1F, 0x46, 0x0D, 0x46, + 0x00, 0x2A, 0x34, 0xDD, + 0x09, 0x4C, 0x77, 0xB1, 0xB4, 0xF9, 0x0A, 0x60, 0x11, 0x46, 0x0F, 0xF0, + 0xD6, 0xFF, 0xB0, 0x42, + 0x28, 0x78, 0x27, 0xDA, 0xFF, 0x28, 0x1C, 0xD2, 0x40, 0x1C, 0x28, 0x70, + 0x00, 0x20, 0xBD, 0xE8, + 0xF0, 0x81, 0x13, 0xE0, 0xB4, 0x10, 0x10, 0x00, 0xC0, 0x04, 0x10, 0x00, + 0xF1, 0x3E, 0x00, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x50, 0x07, 0x10, 0x00, 0x0C, 0xA0, 0x01, 0x20, + 0x9C, 0x4B, 0x01, 0x20, + 0xF0, 0x4B, 0x01, 0x20, 0x88, 0x4C, 0x01, 0x20, 0xD4, 0x56, 0x10, 0x00, + 0xB4, 0xF9, 0x08, 0x60, + 0xDA, 0xE7, 0xE0, 0x69, 0x1F, 0xB1, 0x40, 0xF0, 0x02, 0x00, 0xE0, 0x61, + 0x05, 0xE0, 0x40, 0xF4, + 0x00, 0x60, 0xFA, 0xE7, 0x08, 0xB1, 0x40, 0x1E, 0x28, 0x70, 0x01, 0x20, + 0xD7, 0xE7, 0x2D, 0xE9, + 0xF0, 0x41, 0x1E, 0x46, 0x0D, 0x46, 0x00, 0x2A, 0x1A, 0xDD, 0xFE, 0x4C, + 0x66, 0xB1, 0xB4, 0xF9, + 0x0A, 0x70, 0x11, 0x46, 0x0F, 0xF0, 0x99, 0xFF, 0xB8, 0x42, 0x11, 0xDD, + 0x28, 0x78, 0x50, 0xB1, + 0x10, 0x28, 0x04, 0xD3, 0x10, 0x38, 0x03, 0xE0, 0xB4, 0xF9, 0x08, 0x70, + 0xF1, 0xE7, 0x00, 0x20, + 0x28, 0x70, 0x00, 0x20, 0xBB, 0xE7, 0xE0, 0x69, 0x26, 0xB1, 0x40, 0xF0, + 0x01, 0x00, 0xE0, 0x61, + 0x01, 0x20, 0xB4, 0xE7, 0x40, 0xF4, 0x80, 0x60, 0xF9, 0xE7, 0x2D, 0xE9, + 0xF1, 0x4F, 0x82, 0xB0, + 0x00, 0x25, 0xEC, 0x48, 0x02, 0x9A, 0x2C, 0x46, 0xFF, 0x21, 0x02, 0xB3, + 0xD0, 0xF8, 0x30, 0x90, + 0x02, 0x26, 0x4F, 0xF0, 0x18, 0x0B, 0x89, 0xF8, 0x00, 0x10, 0xD0, 0xF8, + 0x34, 0x80, 0x88, 0xF8, + 0x00, 0x10, 0xB0, 0xF9, 0x0A, 0x70, 0x31, 0x46, 0x00, 0x91, 0x41, 0x69, + 0x00, 0x29, 0x00, 0xDC, + 0x01, 0x25, 0xE0, 0x48, 0x80, 0x69, 0x00, 0x28, 0x00, 0xDC, 0x01, 0x24, + 0xFF, 0xF7, 0x06, 0xFF, + 0xFF, 0xF7, 0xA2, 0xFD, 0x00, 0x98, 0x00, 0xF0, 0xFD, 0xFC, 0x85, 0xB1, + 0x21, 0xE0, 0xD0, 0xF8, + 0x28, 0x90, 0x4F, 0xF4, 0x00, 0x66, 0x4F, 0xF0, 0x18, 0x0B, 0x89, 0xF8, + 0x00, 0x10, 0xD0, 0xF8, + 0x2C, 0x80, 0x88, 0xF8, 0x00, 0x10, 0xB0, 0xF9, 0x08, 0x70, 0x01, 0x21, + 0xDC, 0xE7, 0xDF, 0xF8, + 0x44, 0xA3, 0x3A, 0x46, 0xDA, 0xF8, 0x20, 0x00, 0xDA, 0xF8, 0x14, 0x10, + 0x00, 0x68, 0x00, 0xF0, + 0xF6, 0xFC, 0x01, 0x28, 0x05, 0xD1, 0xDA, 0xF8, 0x1C, 0x10, 0x31, 0x43, + 0x01, 0x25, 0xCA, 0xF8, + 0x1C, 0x10, 0x8C, 0xB9, 0xDF, 0xF8, 0x1C, 0xA3, 0x3A, 0x46, 0xDA, 0xF8, + 0x24, 0x00, 0xDA, 0xF8, + 0x18, 0x10, 0x00, 0x68, 0x00, 0xF0, 0xE3, 0xFC, 0x01, 0x28, 0x05, 0xD1, + 0xDA, 0xF8, 0x1C, 0x10, + 0x31, 0x43, 0x01, 0x24, 0xCA, 0xF8, 0x1C, 0x10, 0x0D, 0xB1, 0x00, 0x2C, + 0x4E, 0xD1, 0x2F, 0x46, + 0x26, 0x46, 0x4F, 0xF0, 0x17, 0x0A, 0x4F, 0xB9, 0xBA, 0x48, 0x02, 0x9B, + 0x01, 0x6A, 0x42, 0x69, + 0x0F, 0x68, 0x49, 0x46, 0x38, 0x46, 0xFF, 0xF7, 0x6A, 0xFF, 0x07, 0x46, + 0x4E, 0xB9, 0xB5, 0x48, + 0x02, 0x9B, 0x41, 0x6A, 0x82, 0x69, 0x0E, 0x68, 0x41, 0x46, 0x30, 0x46, + 0xFF, 0xF7, 0x5F, 0xFF, + 0x06, 0x46, 0xFF, 0xF7, 0xAB, 0xFE, 0xFF, 0xF7, 0x47, 0xFD, 0x00, 0x98, + 0x00, 0xF0, 0xA2, 0xFC, + 0x07, 0xB1, 0x16, 0xB9, 0xBA, 0xF1, 0x01, 0x0A, 0xDD, 0xD2, 0x2F, 0x46, + 0xA9, 0x4D, 0xAB, 0xF1, + 0x01, 0x06, 0x3F, 0xB9, 0x28, 0x6A, 0x02, 0x9B, 0x49, 0x46, 0x00, 0x68, + 0x6A, 0x69, 0xFF, 0xF7, + 0x09, 0xFF, 0x07, 0x46, 0x3C, 0xB9, 0x68, 0x6A, 0x02, 0x9B, 0x41, 0x46, + 0x00, 0x68, 0xAA, 0x69, + 0xFF, 0xF7, 0x00, 0xFF, 0x04, 0x46, 0xFF, 0xF7, 0x89, 0xFE, 0xFF, 0xF7, + 0x25, 0xFD, 0x00, 0x98, + 0x00, 0xF0, 0x80, 0xFC, 0x07, 0xB1, 0x0C, 0xB9, 0x76, 0x1E, 0xE2, 0xD2, + 0x01, 0x2F, 0x05, 0xD1, + 0x01, 0x2C, 0x03, 0xD1, 0xE8, 0x69, 0x20, 0xF4, 0x00, 0x70, 0xE8, 0x61, + 0xBD, 0xE8, 0xFE, 0x8F, + 0x2D, 0xE9, 0xF0, 0x4F, 0x9A, 0x46, 0x91, 0x46, 0x00, 0x22, 0x92, 0x4B, + 0x83, 0x46, 0x14, 0x46, + 0xB3, 0xF9, 0x0C, 0x70, 0x10, 0x46, 0x01, 0x23, 0x90, 0x46, 0x14, 0xE0, + 0x09, 0xEB, 0xE4, 0x05, + 0x04, 0xF0, 0x07, 0x0C, 0x2E, 0x78, 0x03, 0xFA, 0x0C, 0xF5, 0x35, 0x42, + 0x0A, 0xD0, 0x3B, 0xF9, + 0x12, 0x50, 0xBD, 0x42, 0x03, 0xDC, 0x0A, 0xF8, 0x02, 0x30, 0x01, 0x20, + 0x01, 0xE0, 0x0A, 0xF8, + 0x02, 0x80, 0x52, 0x1C, 0x64, 0x1C, 0x8A, 0x42, 0xE8, 0xDB, 0x32, 0xE6, + 0x2D, 0xE9, 0xFF, 0x5F, + 0x00, 0x24, 0x4F, 0xF0, 0x01, 0x08, 0x9A, 0x46, 0x17, 0x46, 0x25, 0x46, + 0xDF, 0xF8, 0xF4, 0x91, + 0x46, 0x46, 0xDD, 0xF8, 0x3C, 0xB0, 0x4E, 0xE0, 0x0A, 0xEB, 0xE5, 0x00, + 0x05, 0xF0, 0x07, 0x01, + 0x00, 0x78, 0x06, 0xFA, 0x01, 0xF2, 0x02, 0x42, 0x44, 0xD0, 0x1B, 0xF8, + 0x04, 0x00, 0x01, 0x28, + 0x3F, 0xD0, 0x00, 0x98, 0xB9, 0xF9, 0x0C, 0x10, 0x30, 0xF9, 0x14, 0x20, + 0x8A, 0x42, 0x1D, 0xDA, + 0x29, 0x46, 0x01, 0x98, 0xFC, 0xF7, 0x87, 0xFA, 0xFF, 0x28, 0x0E, 0xDA, + 0x40, 0x1C, 0xC2, 0xB2, + 0x4F, 0xF0, 0x00, 0x08, 0x29, 0x46, 0x01, 0x98, 0xFC, 0xF7, 0x7F, 0xFA, + 0x00, 0x98, 0x30, 0xF8, + 0x14, 0x10, 0x0E, 0x98, 0x20, 0xF8, 0x14, 0x10, 0x23, 0xE0, 0x0B, 0xF8, + 0x04, 0x60, 0xD9, 0xF8, + 0x1C, 0x10, 0x41, 0xF0, 0x08, 0x01, 0xC9, 0xF8, 0x1C, 0x10, 0x1A, 0xE0, + 0x0E, 0x98, 0x30, 0xF9, + 0x14, 0x00, 0x00, 0x28, 0x13, 0xDD, 0x40, 0x1A, 0xA2, 0xEB, 0x01, 0x01, + 0x00, 0xD5, 0x40, 0x42, + 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0x88, 0x42, 0x09, 0xDC, 0x29, 0x46, + 0x01, 0x98, 0xFC, 0xF7, + 0x5A, 0xFA, 0x40, 0x1E, 0xC2, 0xB2, 0x29, 0x46, 0x01, 0x98, 0xFC, 0xF7, + 0x56, 0xFA, 0x0B, 0xF8, + 0x04, 0x60, 0x64, 0x1C, 0x6D, 0x1C, 0xBC, 0x42, 0xAE, 0xDB, 0x40, 0x46, + 0x04, 0xB0, 0xBD, 0xE8, + 0xF0, 0x9F, 0x2D, 0xE9, 0xFF, 0x5F, 0x00, 0x24, 0x4F, 0xF0, 0x01, 0x08, + 0x9A, 0x46, 0x17, 0x46, + 0x25, 0x46, 0x46, 0x46, 0xDF, 0xF8, 0x2C, 0x91, 0xDD, 0xF8, 0x38, 0xB0, + 0x31, 0xE0, 0x00, 0xBF, + 0x0A, 0xEB, 0xE5, 0x00, 0x05, 0xF0, 0x07, 0x02, 0x01, 0x78, 0x06, 0xFA, + 0x02, 0xF0, 0x08, 0x42, + 0x26, 0xD0, 0x1B, 0xF8, 0x04, 0x00, 0x01, 0x28, 0x21, 0xD0, 0x00, 0x98, + 0x30, 0xF9, 0x14, 0x10, + 0xB9, 0xF9, 0x0C, 0x00, 0x81, 0x42, 0x1A, 0xDD, 0x29, 0x46, 0x01, 0x98, + 0xFC, 0xF7, 0x23, 0xFA, + 0x00, 0x28, 0x0C, 0xDD, 0x4F, 0xF0, 0x00, 0x08, 0x04, 0x28, 0x01, 0xDB, + 0x00, 0x1F, 0x00, 0xE0, + 0x00, 0x20, 0xC2, 0xB2, 0x29, 0x46, 0x01, 0x98, 0xFC, 0xF7, 0x17, 0xFA, + 0x07, 0xE0, 0x0B, 0xF8, + 0x04, 0x60, 0xD9, 0xF8, 0x1C, 0x10, 0x41, 0xF0, 0x04, 0x01, 0xC9, 0xF8, + 0x1C, 0x10, 0x64, 0x1C, + 0x6D, 0x1C, 0xBC, 0x42, 0xCC, 0xDB, 0x40, 0x46, 0xB8, 0xE7, 0x2D, 0xE9, + 0xF0, 0x4F, 0x93, 0xB0, + 0x00, 0x24, 0x25, 0x46, 0x18, 0x21, 0x0C, 0xA8, 0x12, 0xF0, 0xE0, 0xFD, + 0x28, 0x21, 0x02, 0xA8, + 0x12, 0xF0, 0xDC, 0xFD, 0x27, 0x48, 0x41, 0x69, 0x00, 0x29, 0x00, 0xDC, + 0x01, 0x24, 0x82, 0x69, + 0x00, 0x2A, 0x00, 0xDC, 0x01, 0x25, 0x23, 0x4A, 0x81, 0x46, 0x06, 0x46, + 0xFF, 0x23, 0x10, 0x32, + 0x80, 0x6B, 0x00, 0xF0, 0xA6, 0xFB, 0x1F, 0x4A, 0xFF, 0x23, 0x50, 0x32, + 0xB1, 0x69, 0xF0, 0x6B, + 0x00, 0xF0, 0x9F, 0xFB, 0xFF, 0xF7, 0x82, 0xFD, 0xFF, 0xF7, 0x1E, 0xFC, + 0x04, 0x20, 0x00, 0xF0, + 0x79, 0xFB, 0x8C, 0xB1, 0xD9, 0xF8, 0x20, 0x00, 0x16, 0x4A, 0x4E, 0x46, + 0x00, 0x68, 0x0C, 0xAB, + 0x10, 0x32, 0xD9, 0xF8, 0x14, 0x10, 0xFF, 0xF7, 0xFB, 0xFE, 0x01, 0x28, + 0x04, 0xD1, 0xF0, 0x69, + 0x01, 0x24, 0x40, 0xF0, 0x08, 0x00, 0xF0, 0x61, 0x8D, 0xB1, 0xD9, 0xF8, + 0x24, 0x00, 0x0D, 0x4A, + 0x4E, 0x46, 0x00, 0x68, 0x02, 0xAB, 0x50, 0x32, 0xD9, 0xF8, 0x18, 0x10, + 0xFF, 0xF7, 0xE8, 0xFE, + 0x01, 0x28, 0x04, 0xD1, 0xF0, 0x69, 0x01, 0x25, 0x40, 0xF0, 0x08, 0x00, + 0xF0, 0x61, 0x0C, 0xB1, + 0x00, 0x2D, 0x7A, 0xD1, 0x26, 0x46, 0xA8, 0x46, 0x00, 0x27, 0x0D, 0xF1, + 0x30, 0x0B, 0x86, 0xB9, + 0x02, 0xE0, 0x00, 0x00, 0xC0, 0x04, 0x10, 0x00, 0xCD, 0xF8, 0x00, 0xB0, + 0xD9, 0xF8, 0x20, 0x00, + 0xFE, 0x4B, 0xD9, 0xF8, 0x14, 0x20, 0x00, 0x68, 0xD9, 0xF8, 0x38, 0x10, + 0xFF, 0xF7, 0x51, 0xFF, + 0x06, 0x46, 0xB8, 0xF1, 0x00, 0x0F, 0x0D, 0xD1, 0x02, 0xA8, 0x00, 0x90, + 0xD9, 0xF8, 0x24, 0x10, + 0xF6, 0x4B, 0xD9, 0xF8, 0x18, 0x20, 0x08, 0x68, 0x40, 0x33, 0xD9, 0xF8, + 0x3C, 0x10, 0xFF, 0xF7, + 0x40, 0xFF, 0x80, 0x46, 0xFF, 0xF7, 0x2A, 0xFD, 0xFF, 0xF7, 0xC6, 0xFB, + 0x04, 0x20, 0x00, 0xF0, + 0x21, 0xFB, 0x16, 0xB1, 0xB8, 0xF1, 0x00, 0x0F, 0x02, 0xD1, 0x7F, 0x1C, + 0x60, 0x2F, 0xCE, 0xDB, + 0xDF, 0xF8, 0xAC, 0xA3, 0xD9, 0xF8, 0x14, 0x00, 0x26, 0x46, 0x41, 0x00, + 0x0A, 0xF5, 0xE6, 0x68, + 0x4C, 0x46, 0x50, 0x46, 0x12, 0xF0, 0x30, 0xFD, 0xA0, 0x69, 0x41, 0x00, + 0x40, 0x46, 0x12, 0xF0, + 0x2B, 0xFD, 0x00, 0x27, 0xFF, 0xF7, 0xA8, 0xFB, 0x04, 0x20, 0x00, 0xF0, + 0x03, 0xFB, 0x4E, 0xB9, + 0xCD, 0xE9, 0x00, 0xAB, 0x20, 0x6A, 0xDD, 0x4B, 0x62, 0x69, 0x00, 0x68, + 0xA1, 0x6B, 0xFF, 0xF7, + 0xAD, 0xFE, 0x06, 0x46, 0x5D, 0xB9, 0x02, 0xA8, 0xCD, 0xE9, 0x00, 0x80, + 0x60, 0x6A, 0xD7, 0x4B, + 0xA2, 0x69, 0x00, 0x68, 0x40, 0x33, 0xE1, 0x6B, 0xFF, 0xF7, 0xA0, 0xFE, + 0x05, 0x46, 0xFF, 0xF7, + 0xED, 0xFC, 0xFF, 0xF7, 0x89, 0xFB, 0x04, 0x20, 0x00, 0xF0, 0xE4, 0xFA, + 0x06, 0xB1, 0x15, 0xB9, + 0x7F, 0x1C, 0x60, 0x2F, 0xD6, 0xDB, 0x01, 0x2E, 0x07, 0xD1, 0x01, 0x2D, + 0x05, 0xD1, 0xE0, 0x69, + 0x81, 0x05, 0x02, 0xD5, 0x20, 0xF4, 0x00, 0x70, 0xE0, 0x61, 0x13, 0xB0, + 0xB9, 0xE4, 0x2D, 0xE9, + 0xF0, 0x41, 0x0F, 0x46, 0xC5, 0x49, 0x16, 0x46, 0x02, 0x46, 0x10, 0x39, + 0xDD, 0xE9, 0x06, 0x05, + 0xB1, 0xF9, 0x0E, 0xC0, 0x01, 0x24, 0x62, 0x45, 0x11, 0xDD, 0x1D, 0x68, + 0xA0, 0xF1, 0x7F, 0x02, + 0x95, 0x42, 0x07, 0xDD, 0x2A, 0x1A, 0x31, 0x46, 0x38, 0x46, 0x1A, 0x60, + 0xFC, 0xF7, 0xF4, 0xF8, + 0x00, 0x24, 0x11, 0xE0, 0xC8, 0x69, 0x40, 0xF0, 0x40, 0x00, 0xC8, 0x61, + 0x0C, 0xE0, 0x01, 0x21, + 0x29, 0x70, 0x19, 0x68, 0xC0, 0xF1, 0x7F, 0x02, 0x91, 0x42, 0x05, 0xDA, + 0x0A, 0x18, 0x31, 0x46, + 0x38, 0x46, 0x1A, 0x60, 0xFC, 0xF7, 0xE0, 0xF8, 0x20, 0x46, 0x30, 0xE5, + 0x2D, 0xE9, 0xFF, 0x4F, + 0x00, 0x24, 0x85, 0xB0, 0x91, 0x46, 0x06, 0x46, 0x25, 0x46, 0xA2, 0x46, + 0x78, 0xE0, 0x08, 0x98, + 0x05, 0xF0, 0x07, 0x03, 0x00, 0xEB, 0xE5, 0x00, 0x7F, 0x22, 0x01, 0x78, + 0x01, 0x20, 0x98, 0x40, + 0x08, 0x42, 0x03, 0x92, 0x6B, 0xD0, 0x29, 0x46, 0x06, 0x98, 0xFC, 0xF7, + 0xC5, 0xF8, 0x00, 0x20, + 0x8D, 0xF8, 0x08, 0x00, 0x80, 0x46, 0x4F, 0xF0, 0x10, 0x0B, 0x00, 0xBF, + 0xFF, 0xF7, 0x24, 0xFB, + 0x08, 0x20, 0x00, 0xF0, 0x7F, 0xFA, 0x02, 0xAF, 0xCD, 0xE9, 0x00, 0xB7, + 0x36, 0xF9, 0x14, 0x00, + 0x03, 0xAB, 0x2A, 0x46, 0x06, 0x99, 0xFF, 0xF7, 0xA2, 0xFF, 0x20, 0xB9, + 0x08, 0xF1, 0x01, 0x08, + 0xB8, 0xF1, 0x18, 0x0F, 0xEA, 0xDB, 0x9D, 0xF8, 0x08, 0x00, 0xE0, 0xB3, + 0x00, 0x20, 0x8D, 0xF8, + 0x08, 0x00, 0x80, 0x46, 0x4F, 0xF0, 0x04, 0x0B, 0xFF, 0xF7, 0x06, 0xFB, + 0x08, 0x20, 0x00, 0xF0, + 0x61, 0xFA, 0xCD, 0xE9, 0x00, 0xB7, 0x36, 0xF9, 0x14, 0x00, 0x03, 0xAB, + 0x2A, 0x46, 0x06, 0x99, + 0xFF, 0xF7, 0x85, 0xFF, 0x20, 0xB9, 0x08, 0xF1, 0x01, 0x08, 0xB8, 0xF1, + 0x18, 0x0F, 0xEB, 0xDB, + 0x9D, 0xF8, 0x08, 0x00, 0xF8, 0xB1, 0x00, 0x20, 0x8D, 0xF8, 0x08, 0x00, + 0x80, 0x46, 0x4F, 0xF0, + 0x01, 0x0B, 0x00, 0xBF, 0xFF, 0xF7, 0xE8, 0xFA, 0x08, 0x20, 0x00, 0xF0, + 0x43, 0xFA, 0xCD, 0xE9, + 0x00, 0xB7, 0x36, 0xF9, 0x14, 0x00, 0x03, 0xAB, 0x2A, 0x46, 0x06, 0x99, + 0xFF, 0xF7, 0x67, 0xFF, + 0x78, 0xB1, 0x9D, 0xF8, 0x08, 0x00, 0x01, 0x28, 0x10, 0xD0, 0x03, 0x9A, + 0x29, 0x46, 0x52, 0x1E, + 0x03, 0x92, 0x06, 0x98, 0x00, 0xE0, 0x09, 0xE0, 0xFC, 0xF7, 0x66, 0xF8, + 0x0A, 0xF1, 0x01, 0x0A, + 0x04, 0xE0, 0x08, 0xF1, 0x01, 0x08, 0xB8, 0xF1, 0x18, 0x0F, 0xDB, 0xDB, + 0x64, 0x1C, 0x6D, 0x1C, + 0x4C, 0x45, 0x84, 0xDB, 0xCA, 0x45, 0x02, 0xD0, 0x00, 0x20, 0x09, 0xB0, + 0xCD, 0xE5, 0x01, 0x20, + 0xFB, 0xE7, 0x70, 0xB5, 0x69, 0x4C, 0x01, 0x25, 0x10, 0x3C, 0xA2, 0x69, + 0x00, 0x2A, 0x08, 0xDD, + 0x60, 0x6A, 0x04, 0xF1, 0x50, 0x03, 0x61, 0x6C, 0x00, 0x68, 0xFF, 0xF7, + 0x67, 0xFF, 0x00, 0xF0, + 0x01, 0x05, 0x62, 0x69, 0x00, 0x2A, 0x06, 0xDD, 0x20, 0x6A, 0x60, 0x4B, + 0x21, 0x6C, 0x00, 0x68, + 0xFF, 0xF7, 0x5C, 0xFF, 0x05, 0x40, 0x28, 0x46, 0x70, 0xBD, 0x70, 0xB5, + 0x5B, 0x4C, 0x00, 0x26, + 0x10, 0x3C, 0x05, 0x46, 0xE6, 0x61, 0x01, 0x28, 0x5B, 0xD0, 0x02, 0x2D, + 0x5B, 0xD0, 0x01, 0x20, + 0x20, 0x70, 0x60, 0x79, 0x60, 0xB1, 0x00, 0x23, 0x54, 0x4A, 0x61, 0x69, + 0xA0, 0x6B, 0x00, 0xF0, + 0x08, 0xFA, 0x52, 0x4A, 0x00, 0x23, 0x40, 0x32, 0xA1, 0x69, 0xE0, 0x6B, + 0x00, 0xF0, 0x01, 0xFA, + 0xA0, 0x79, 0x50, 0xB1, 0x4D, 0x49, 0x62, 0x69, 0x20, 0x6C, 0xFC, 0xF7, + 0x20, 0xF8, 0x4B, 0x49, + 0xA2, 0x69, 0x40, 0x31, 0x60, 0x6C, 0xFC, 0xF7, 0x1A, 0xF8, 0xE0, 0x78, + 0x10, 0xB1, 0x00, 0x20, + 0xFF, 0xF7, 0xAB, 0xFC, 0x20, 0x79, 0x60, 0xB1, 0xE0, 0x78, 0x38, 0xB1, + 0x61, 0x78, 0xA0, 0x6A, + 0x00, 0xF0, 0xD5, 0xF9, 0x61, 0x78, 0xE0, 0x6A, 0x00, 0xF0, 0xD1, 0xF9, + 0x01, 0x20, 0xFF, 0xF7, + 0x9C, 0xFC, 0x60, 0x79, 0x08, 0xB1, 0xFF, 0xF7, 0x18, 0xFE, 0x01, 0x2D, + 0x25, 0xD0, 0x02, 0x2D, + 0x25, 0xD0, 0x26, 0x70, 0xFF, 0xF7, 0x58, 0xFA, 0xA0, 0x79, 0x60, 0xB1, + 0x20, 0x79, 0x38, 0xB1, + 0xA1, 0x78, 0x20, 0x6B, 0x00, 0xF0, 0xBB, 0xF9, 0xA1, 0x78, 0x60, 0x6B, + 0x00, 0xF0, 0xB7, 0xF9, + 0xE0, 0x79, 0xFF, 0xF7, 0x8E, 0xFF, 0xFF, 0xF7, 0x47, 0xFA, 0x01, 0x2D, + 0x12, 0xD0, 0x02, 0x2D, + 0x12, 0xD0, 0x10, 0x21, 0xE0, 0x69, 0x00, 0xF0, 0xD1, 0xF9, 0xE0, 0x69, + 0x78, 0xB1, 0x00, 0x20, + 0x70, 0xBD, 0x03, 0x20, 0xA4, 0xE7, 0x05, 0x20, 0xA2, 0xE7, 0x02, 0x20, + 0x00, 0xE0, 0x04, 0x20, + 0x20, 0x70, 0xD7, 0xE7, 0x40, 0x21, 0xED, 0xE7, 0x4F, 0xF4, 0x00, 0x71, + 0xEA, 0xE7, 0x01, 0x20, + 0x70, 0xBD, 0x70, 0xB5, 0x21, 0x4D, 0x0C, 0x46, 0x10, 0x3D, 0x02, 0x28, + 0x26, 0xD0, 0x11, 0xF0, + 0xE6, 0xFF, 0x28, 0x61, 0x11, 0xF0, 0xE5, 0xFF, 0xC5, 0xE9, 0x14, 0x01, + 0x04, 0x21, 0x1B, 0x48, + 0xFC, 0xF7, 0x71, 0xFB, 0x68, 0x61, 0x19, 0x48, 0x08, 0x21, 0x40, 0x30, + 0xFC, 0xF7, 0x6B, 0xFB, + 0xA8, 0x61, 0x04, 0xF1, 0x90, 0x00, 0xA8, 0x62, 0x40, 0x1C, 0xE8, 0x62, + 0x40, 0x1C, 0x28, 0x63, + 0x40, 0x1C, 0x68, 0x63, 0x4B, 0x38, 0xA8, 0x63, 0x20, 0x30, 0xC5, 0xE9, + 0x0F, 0x04, 0x48, 0x38, + 0x68, 0x64, 0x74, 0x30, 0x95, 0x34, 0xC5, 0xE9, 0x12, 0x04, 0x70, 0xBD, + 0x11, 0xF0, 0xC7, 0xFF, + 0x28, 0x61, 0x11, 0xF0, 0xC6, 0xFF, 0xD7, 0xE7, 0x10, 0xB5, 0x0A, 0x49, + 0x00, 0x20, 0xFF, 0xF7, + 0xC8, 0xFF, 0x06, 0x48, 0x08, 0x49, 0x10, 0x38, 0x08, 0x4A, 0x01, 0x62, + 0x09, 0x1D, 0x41, 0x62, + 0x13, 0x68, 0x93, 0xF8, 0x88, 0x11, 0x11, 0xF0, 0x01, 0x04, 0x09, 0xE0, + 0xD0, 0x04, 0x10, 0x00, + 0xD4, 0x56, 0x10, 0x00, 0x38, 0x99, 0x01, 0x20, 0xCC, 0x10, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0xC4, 0x70, 0x4F, 0xF0, 0x00, 0x01, 0x04, 0xD0, 0x83, 0x6A, 0x19, 0x70, + 0xC3, 0x6A, 0x19, 0x70, + 0x08, 0xE0, 0x84, 0x6A, 0x93, 0xF8, 0x92, 0x31, 0x23, 0x70, 0x13, 0x68, + 0xC4, 0x6A, 0x93, 0xF8, + 0x93, 0x31, 0x23, 0x70, 0x13, 0x68, 0x93, 0xF8, 0x88, 0x41, 0xC4, 0xF3, + 0x40, 0x04, 0x04, 0x71, + 0x14, 0xB1, 0x03, 0x6B, 0x19, 0x70, 0x06, 0xE0, 0x93, 0xF8, 0x94, 0x11, + 0x03, 0x6B, 0x19, 0x70, + 0x11, 0x68, 0x91, 0xF8, 0x95, 0x11, 0x43, 0x6B, 0x19, 0x70, 0x11, 0x68, + 0x91, 0xF8, 0x88, 0x21, + 0xC2, 0xF3, 0x80, 0x03, 0x43, 0x71, 0xC2, 0xF3, 0xC0, 0x02, 0x82, 0x71, + 0xB1, 0xF8, 0x8A, 0x21, + 0x02, 0x81, 0xB1, 0xF8, 0x8C, 0x21, 0x42, 0x81, 0xB1, 0xF8, 0x8E, 0x21, + 0x82, 0x81, 0xB1, 0xF8, + 0x90, 0x21, 0xC2, 0x81, 0x91, 0xF8, 0x96, 0x21, 0x42, 0x70, 0x91, 0xF8, + 0x97, 0x21, 0x82, 0x70, + 0x91, 0xF8, 0x34, 0x11, 0xC1, 0xF3, 0x40, 0x01, 0xC1, 0x71, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0x20, + 0xF3, 0xE6, 0x10, 0xB5, 0xAC, 0x49, 0x01, 0x20, 0xFF, 0xF7, 0x63, 0xFF, + 0xAC, 0x48, 0xAB, 0x49, + 0x01, 0x62, 0x00, 0x21, 0xC0, 0xE9, 0x14, 0x11, 0x0A, 0x46, 0x81, 0x61, + 0xA9, 0x49, 0x0B, 0x68, + 0x93, 0xF8, 0xA0, 0x41, 0x14, 0xF0, 0x01, 0x04, 0xC4, 0x70, 0x04, 0xD0, + 0x83, 0x6A, 0x1A, 0x70, + 0xC3, 0x6A, 0x1A, 0x70, 0x08, 0xE0, 0x84, 0x6A, 0x93, 0xF8, 0xAA, 0x31, + 0x23, 0x70, 0x0B, 0x68, + 0xC4, 0x6A, 0x93, 0xF8, 0xAB, 0x31, 0x23, 0x70, 0x0B, 0x68, 0x93, 0xF8, + 0xA0, 0x41, 0xC4, 0xF3, + 0x40, 0x04, 0x04, 0x71, 0x14, 0xB1, 0x03, 0x6B, 0x1A, 0x70, 0x06, 0xE0, + 0x93, 0xF8, 0xAC, 0x21, + 0x03, 0x6B, 0x1A, 0x70, 0x0A, 0x68, 0x92, 0xF8, 0xAD, 0x21, 0x43, 0x6B, + 0x1A, 0x70, 0x09, 0x68, + 0x91, 0xF8, 0xA0, 0x21, 0xC2, 0xF3, 0x80, 0x03, 0x43, 0x71, 0xC2, 0xF3, + 0xC0, 0x02, 0x82, 0x71, + 0xB1, 0xF8, 0xA2, 0x21, 0x02, 0x81, 0xB1, 0xF8, 0xA4, 0x21, 0x42, 0x81, + 0xB1, 0xF8, 0xA6, 0x21, + 0x82, 0x81, 0xB1, 0xF8, 0xA8, 0x21, 0xC2, 0x81, 0x91, 0xF8, 0xAE, 0x21, + 0x42, 0x70, 0x91, 0xF8, + 0xAF, 0x21, 0x82, 0x70, 0x91, 0xF8, 0x84, 0x19, 0xC1, 0xF3, 0x40, 0x01, + 0xC1, 0x71, 0xBD, 0xE8, + 0x10, 0x40, 0x01, 0x20, 0x99, 0xE6, 0x80, 0x49, 0x10, 0xB5, 0x98, 0x31, + 0x02, 0x20, 0xFF, 0xF7, + 0x08, 0xFF, 0x7E, 0x49, 0x7E, 0x48, 0x09, 0x1D, 0x01, 0x62, 0x7E, 0x49, + 0x0B, 0x68, 0x93, 0xF8, + 0xB0, 0x21, 0x12, 0xF0, 0x01, 0x04, 0xC4, 0x70, 0x4F, 0xF0, 0x00, 0x02, + 0x04, 0xD0, 0x83, 0x6A, + 0x1A, 0x70, 0xC3, 0x6A, 0x1A, 0x70, 0x08, 0xE0, 0x84, 0x6A, 0x93, 0xF8, + 0xBA, 0x31, 0x23, 0x70, + 0x0B, 0x68, 0xC4, 0x6A, 0x93, 0xF8, 0xBB, 0x31, 0x23, 0x70, 0x0C, 0x68, + 0x94, 0xF8, 0xB0, 0x31, + 0xC3, 0xF3, 0x40, 0x03, 0x03, 0x71, 0x13, 0xB1, 0x03, 0x6B, 0x1A, 0x70, + 0x06, 0xE0, 0x03, 0x6B, + 0x94, 0xF8, 0xBC, 0x21, 0x1A, 0x70, 0x0A, 0x68, 0x92, 0xF8, 0xBD, 0x21, + 0x43, 0x6B, 0x1A, 0x70, + 0x09, 0x68, 0x91, 0xF8, 0xB0, 0x21, 0xC2, 0xF3, 0x80, 0x03, 0x43, 0x71, + 0xC2, 0xF3, 0xC0, 0x02, + 0x82, 0x71, 0xB1, 0xF8, 0xB2, 0x21, 0x02, 0x81, 0xB1, 0xF8, 0xB4, 0x21, + 0x42, 0x81, 0xB1, 0xF8, + 0xB6, 0x21, 0x82, 0x81, 0xB1, 0xF8, 0xB8, 0x21, 0xC2, 0x81, 0x91, 0xF8, + 0xBE, 0x21, 0x42, 0x70, + 0x91, 0xF8, 0xBF, 0x11, 0x81, 0x70, 0x01, 0x21, 0xC1, 0x71, 0xBD, 0xE8, + 0x10, 0x40, 0x02, 0x20, + 0x43, 0xE6, 0x2D, 0xE9, 0xF0, 0x41, 0x07, 0x46, 0x01, 0x24, 0x00, 0x20, + 0xFB, 0xF7, 0xC9, 0xFC, + 0x02, 0x20, 0xFB, 0xF7, 0xC6, 0xFC, 0x54, 0x49, 0x01, 0x20, 0x08, 0x70, + 0x53, 0x4E, 0x78, 0x07, + 0x4F, 0xF0, 0x00, 0x05, 0x4F, 0xF0, 0xA5, 0x08, 0x0A, 0xD5, 0xFF, 0xF7, + 0xD5, 0xFE, 0x10, 0xF0, + 0x01, 0x04, 0x05, 0xD0, 0x30, 0x68, 0xC5, 0x77, 0x80, 0xF8, 0x20, 0x50, + 0x80, 0xF8, 0x1E, 0x80, + 0x38, 0x07, 0x0A, 0xD5, 0xFF, 0xF7, 0x2D, 0xFF, 0x20, 0x40, 0x04, 0x00, + 0x05, 0xD0, 0x30, 0x68, + 0x00, 0xF8, 0x22, 0x5F, 0x45, 0x70, 0x00, 0xF8, 0x01, 0x8C, 0x38, 0x06, + 0x0A, 0xD5, 0xFF, 0xF7, + 0x7A, 0xFF, 0x20, 0x40, 0x04, 0x00, 0x05, 0xD0, 0x30, 0x68, 0x00, 0xF8, + 0x27, 0x5F, 0x45, 0x70, + 0x00, 0xF8, 0x01, 0x8C, 0x02, 0x20, 0xFB, 0xF7, 0xAF, 0xFC, 0x00, 0x20, + 0xFB, 0xF7, 0xAC, 0xFC, + 0x20, 0x46, 0x5A, 0xE5, 0x3A, 0x49, 0x4A, 0x78, 0x02, 0x42, 0x07, 0xD0, + 0x08, 0x78, 0xAA, 0x28, + 0x04, 0xD1, 0x08, 0x78, 0xAA, 0x28, 0xFC, 0xD0, 0xAA, 0x20, 0x08, 0x70, + 0x70, 0x47, 0x02, 0x78, + 0x8A, 0x42, 0x01, 0xD9, 0x51, 0x1A, 0x00, 0xE0, 0x00, 0x21, 0x01, 0x70, + 0x70, 0x47, 0x10, 0xB5, + 0x14, 0x46, 0x0F, 0xF0, 0x42, 0xFA, 0xA0, 0x42, 0x01, 0xDC, 0x01, 0x20, + 0x10, 0xBD, 0x00, 0x20, + 0x10, 0xBD, 0xF0, 0xB5, 0x00, 0x25, 0x2C, 0x46, 0x01, 0x26, 0x0C, 0xE0, + 0x02, 0xEB, 0xE4, 0x07, + 0x04, 0xF0, 0x07, 0x0C, 0x3F, 0x78, 0x06, 0xFA, 0x0C, 0xFE, 0x1E, 0xEA, + 0x07, 0x0F, 0x01, 0xD0, + 0x03, 0x55, 0x6D, 0x1C, 0x64, 0x1C, 0x8D, 0x42, 0xF0, 0xDB, 0xF0, 0xBD, + 0x70, 0xB5, 0x04, 0x46, + 0x0D, 0x46, 0xC0, 0x07, 0x02, 0xD0, 0x83, 0x20, 0x0D, 0xF0, 0x78, 0xFB, + 0xA0, 0x07, 0x03, 0xD5, + 0x29, 0x46, 0x84, 0x20, 0x0D, 0xF0, 0x72, 0xFB, 0x60, 0x07, 0x03, 0xD5, + 0x29, 0x46, 0x85, 0x20, + 0x0D, 0xF0, 0x6C, 0xFB, 0x20, 0x07, 0x03, 0xD5, 0x29, 0x46, 0x86, 0x20, + 0x0D, 0xF0, 0x66, 0xFB, + 0x60, 0x06, 0x03, 0xD5, 0x29, 0x46, 0x8B, 0x20, 0x0D, 0xF0, 0x60, 0xFB, + 0x20, 0x06, 0x03, 0xD5, + 0x29, 0x46, 0x8C, 0x20, 0x0D, 0xF0, 0x5A, 0xFB, 0xE0, 0x05, 0x03, 0xD5, + 0x29, 0x46, 0x87, 0x20, + 0x0D, 0xF0, 0x54, 0xFB, 0xA0, 0x05, 0x05, 0xD5, 0x29, 0x46, 0xBD, 0xE8, + 0x70, 0x40, 0x88, 0x20, + 0x0D, 0xF0, 0x4C, 0xBB, 0x70, 0xBD, 0x00, 0x00, 0xD0, 0x99, 0x01, 0x20, + 0xDC, 0x10, 0x10, 0x00, + 0xC0, 0x04, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x78, 0x07, 0x10, 0x00, + 0x50, 0x07, 0x10, 0x00, + 0x08, 0x00, 0x00, 0x20, 0x08, 0xB5, 0x4E, 0x4E, 0x4E, 0x4D, 0x00, 0x24, + 0x00, 0x22, 0x6B, 0x46, + 0x31, 0x46, 0x10, 0x46, 0xFB, 0xF7, 0x76, 0xFB, 0x00, 0x98, 0x81, 0x07, + 0x32, 0xD5, 0xFB, 0xF7, + 0xE7, 0xF9, 0x49, 0x48, 0x07, 0x68, 0x04, 0x60, 0xFB, 0xF7, 0xE0, 0xF9, + 0x17, 0xF0, 0x53, 0x0F, + 0x02, 0xD0, 0x38, 0x46, 0xFE, 0xF7, 0xB2, 0xFE, 0x17, 0xF4, 0xD6, 0x7F, + 0x02, 0xD0, 0x38, 0x46, + 0xFF, 0xF7, 0x27, 0xFF, 0xB8, 0x05, 0x13, 0xD5, 0x28, 0x68, 0x90, 0xF8, + 0x70, 0x01, 0x80, 0x07, + 0x02, 0xD5, 0x01, 0x20, 0xFE, 0xF7, 0xEF, 0xFD, 0x28, 0x68, 0x90, 0xF8, + 0x88, 0x11, 0xC9, 0x06, + 0x03, 0xD4, 0x90, 0xF8, 0xA0, 0x01, 0xC0, 0x06, 0x02, 0xD5, 0x01, 0x20, + 0xFF, 0xF7, 0x3B, 0xF9, + 0x78, 0x05, 0x05, 0xD5, 0x00, 0x20, 0xFE, 0xF7, 0xDE, 0xFD, 0x00, 0x20, + 0xFF, 0xF7, 0x33, 0xF9, + 0x02, 0x21, 0x58, 0xE0, 0xC1, 0x05, 0x0C, 0xD5, 0xFB, 0xF7, 0xB2, 0xF9, + 0x2F, 0x48, 0x07, 0x68, + 0x04, 0x60, 0xFB, 0xF7, 0xAB, 0xF9, 0x38, 0x46, 0xFC, 0xF7, 0x9B, 0xFF, + 0x4F, 0xF4, 0x80, 0x71, + 0x49, 0xE0, 0x81, 0x05, 0x04, 0xD5, 0xFE, 0xF7, 0x46, 0xF9, 0x4F, 0xF4, + 0x00, 0x71, 0x42, 0xE0, + 0x41, 0x05, 0x15, 0xD5, 0xFB, 0xF7, 0x9C, 0xF9, 0x25, 0x48, 0x07, 0x68, + 0x04, 0x60, 0xFB, 0xF7, + 0x95, 0xF9, 0xF8, 0x07, 0x01, 0xD0, 0xFD, 0xF7, 0x39, 0xFD, 0xB8, 0x07, + 0x01, 0xD5, 0xFD, 0xF7, + 0xB5, 0xFD, 0x78, 0x07, 0x01, 0xD5, 0xFD, 0xF7, 0x45, 0xFD, 0x4F, 0xF4, + 0x80, 0x61, 0x2A, 0xE0, + 0x01, 0x06, 0x0B, 0xD5, 0xFB, 0xF7, 0x84, 0xF9, 0x1A, 0x48, 0x07, 0x68, + 0x04, 0x60, 0xFB, 0xF7, + 0x7D, 0xF9, 0x38, 0x46, 0xFE, 0xF7, 0x70, 0xF8, 0x80, 0x21, 0x1C, 0xE0, + 0x81, 0x02, 0x0C, 0xD5, + 0xFB, 0xF7, 0x76, 0xF9, 0x14, 0x48, 0x07, 0x68, 0x04, 0x60, 0xFB, 0xF7, + 0x6F, 0xF9, 0x38, 0x46, + 0xFD, 0xF7, 0x9C, 0xFC, 0x4F, 0xF4, 0x00, 0x11, 0x0D, 0xE0, 0xC1, 0x04, + 0x04, 0xD5, 0xFE, 0xF7, + 0x31, 0xFF, 0x4F, 0xF4, 0x80, 0x51, 0x06, 0xE0, 0x00, 0x05, 0x7F, 0xF5, + 0x6F, 0xAF, 0xFE, 0xF7, + 0x45, 0xFF, 0x4F, 0xF4, 0x00, 0x61, 0x00, 0x20, 0xFB, 0xF7, 0xC7, 0xFA, + 0x66, 0xE7, 0x00, 0x00, + 0x83, 0x9F, 0x30, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x58, 0x07, 0x10, 0x00, + 0x54, 0x07, 0x10, 0x00, + 0x60, 0x07, 0x10, 0x00, 0x64, 0x07, 0x10, 0x00, 0x5C, 0x07, 0x10, 0x00, + 0x20, 0x48, 0x10, 0xB5, + 0x01, 0x68, 0x20, 0x48, 0x02, 0x68, 0x13, 0x46, 0x92, 0xEA, 0x01, 0x0F, + 0x28, 0xD0, 0x1E, 0x4A, + 0xCC, 0x07, 0x12, 0x68, 0x25, 0xD0, 0x92, 0xF8, 0x21, 0x43, 0xE4, 0x07, + 0x02, 0xD0, 0x43, 0xF0, + 0x01, 0x03, 0x03, 0x60, 0x8B, 0x07, 0x1F, 0xD5, 0x92, 0xF8, 0x40, 0x33, + 0xDB, 0x07, 0x03, 0xD0, + 0x03, 0x68, 0x43, 0xF0, 0x02, 0x03, 0x03, 0x60, 0x0B, 0x07, 0x19, 0xD5, + 0x92, 0xF8, 0x60, 0x33, + 0xDB, 0x07, 0x03, 0xD0, 0x03, 0x68, 0x43, 0xF0, 0x08, 0x03, 0x03, 0x60, + 0x49, 0x06, 0x13, 0xD5, + 0x92, 0xF8, 0x60, 0x13, 0xC9, 0x07, 0x03, 0xD0, 0x01, 0x68, 0x41, 0xF0, + 0x40, 0x01, 0x01, 0x60, + 0x10, 0xBD, 0x23, 0xF0, 0x01, 0x03, 0xDC, 0xE7, 0x03, 0x68, 0x23, 0xF0, + 0x02, 0x03, 0xE2, 0xE7, + 0x03, 0x68, 0x23, 0xF0, 0x08, 0x03, 0xE8, 0xE7, 0x01, 0x68, 0x21, 0xF0, + 0x40, 0x01, 0xEE, 0xE7, + 0x70, 0x07, 0x10, 0x00, 0x48, 0x05, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x2D, 0xE9, 0xF0, 0x47, + 0xDF, 0xF8, 0x60, 0x92, 0x98, 0x4C, 0x00, 0x25, 0xD9, 0xF8, 0x00, 0x10, + 0x91, 0xF8, 0x31, 0x00, + 0x84, 0xF8, 0x30, 0x00, 0x91, 0xF8, 0x30, 0x20, 0x94, 0x49, 0x84, 0xF8, + 0x31, 0x20, 0x50, 0x43, + 0x09, 0x78, 0x84, 0xF8, 0x33, 0x10, 0x92, 0x49, 0x21, 0x60, 0x34, 0x39, + 0x06, 0xB2, 0x8B, 0x7B, + 0x84, 0xF8, 0x2D, 0x30, 0x88, 0x46, 0x77, 0x00, 0x0F, 0xE0, 0x2A, 0x46, + 0x31, 0x46, 0xD8, 0xF8, + 0x08, 0x00, 0x0E, 0xF0, 0x32, 0xF9, 0x01, 0x46, 0x22, 0x68, 0x06, 0xFB, + 0x05, 0xF0, 0x02, 0xEB, + 0x40, 0x00, 0x3A, 0x46, 0x12, 0xF0, 0x09, 0xF8, 0x6D, 0x1C, 0x94, 0xF8, + 0x2D, 0x00, 0xA8, 0x42, + 0xEB, 0xDC, 0x84, 0x48, 0x84, 0x49, 0x00, 0x78, 0x09, 0x78, 0x08, 0x43, + 0x40, 0x07, 0x11, 0xD5, + 0x82, 0x48, 0x60, 0x60, 0xD9, 0xF8, 0x00, 0x10, 0x91, 0xF8, 0xF1, 0x11, + 0x89, 0x07, 0x4A, 0x0F, + 0x94, 0xF8, 0x31, 0x10, 0x92, 0x1C, 0x4A, 0x43, 0xD8, 0xF8, 0x10, 0x10, + 0xBD, 0xE8, 0xF0, 0x47, + 0x11, 0xF0, 0xEB, 0xBF, 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xF8, 0x43, + 0x75, 0x48, 0xDF, 0xF8, + 0xD8, 0x81, 0x00, 0x27, 0x05, 0x68, 0xD8, 0xF8, 0x00, 0x00, 0x05, 0x43, + 0x01, 0x20, 0xFB, 0xF7, + 0xC8, 0xFA, 0x38, 0x21, 0x6C, 0x48, 0x12, 0xF0, 0x79, 0xF8, 0xE8, 0x07, + 0x06, 0xD0, 0xFF, 0xF7, + 0x9D, 0xFF, 0xE8, 0x06, 0x01, 0xD5, 0x00, 0xF0, 0x9B, 0xF8, 0x01, 0x27, + 0x68, 0x4E, 0x66, 0x4C, + 0xA8, 0x07, 0xA6, 0xF1, 0x34, 0x06, 0x0A, 0xD5, 0x69, 0x48, 0xA0, 0x60, + 0x68, 0x49, 0x70, 0x69, + 0x89, 0x1E, 0x01, 0x27, 0x02, 0x68, 0x41, 0xF8, 0x02, 0x2F, 0x40, 0x68, + 0x48, 0x60, 0xA8, 0x05, + 0x11, 0xD5, 0x62, 0x4F, 0xCA, 0x3F, 0xA7, 0x61, 0x11, 0xF0, 0x81, 0xFC, + 0x00, 0x90, 0x04, 0x21, + 0x68, 0x46, 0xFC, 0xF7, 0x08, 0xF8, 0x84, 0xF8, 0x32, 0x00, 0xF0, 0x6A, + 0x01, 0x68, 0x39, 0x60, + 0x40, 0x68, 0x78, 0x60, 0x01, 0x27, 0x5B, 0x48, 0x00, 0x68, 0xC4, 0xE9, + 0x07, 0x05, 0xD8, 0xF8, + 0x00, 0x00, 0x60, 0x62, 0x70, 0x68, 0xA0, 0x62, 0xF0, 0x7B, 0x84, 0xF8, + 0x35, 0x00, 0x96, 0xF8, + 0x30, 0x00, 0x55, 0x4E, 0x84, 0xF8, 0x36, 0x00, 0x30, 0x78, 0x84, 0xF8, + 0x2C, 0x00, 0xE8, 0x07, + 0x1A, 0xD0, 0xE8, 0x06, 0x18, 0xD5, 0x47, 0x4D, 0x28, 0x68, 0x90, 0xF8, + 0x50, 0x02, 0xC0, 0x07, + 0x06, 0xD0, 0x00, 0xF0, 0xF4, 0xFD, 0x18, 0xB9, 0xE0, 0x69, 0x40, 0xF0, + 0x10, 0x00, 0xE0, 0x61, + 0x28, 0x68, 0x90, 0xF8, 0x80, 0x02, 0xC0, 0x07, 0x06, 0xD0, 0x00, 0xF0, + 0xE8, 0xFD, 0x18, 0xB9, + 0xE0, 0x69, 0x40, 0xF0, 0x20, 0x00, 0xE0, 0x61, 0x01, 0x20, 0xFB, 0xF7, + 0x7D, 0xFA, 0x00, 0x2F, + 0x0C, 0xD0, 0x30, 0x78, 0x05, 0x28, 0x07, 0xD0, 0x06, 0x28, 0x05, 0xD0, + 0x01, 0x21, 0xBD, 0xE8, + 0xF8, 0x43, 0x02, 0x20, 0xFB, 0xF7, 0x75, 0xB9, 0x02, 0x21, 0xF8, 0xE7, + 0xBD, 0xE8, 0xF8, 0x83, + 0x3A, 0x48, 0x10, 0xB5, 0x00, 0x78, 0x00, 0x28, 0x29, 0xD1, 0x31, 0x4C, + 0x34, 0x3C, 0xD4, 0xE9, + 0x06, 0x01, 0x00, 0xF0, 0xC7, 0xFD, 0x94, 0xF8, 0x31, 0x10, 0xA0, 0x6A, + 0x00, 0xF0, 0xC3, 0xFC, + 0xFF, 0xF7, 0x6A, 0xFF, 0x27, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x60, 0x03, + 0xC1, 0x07, 0x16, 0xD0, + 0x81, 0x07, 0x14, 0xD5, 0x00, 0x24, 0x40, 0x09, 0x12, 0xF0, 0x6C, 0xF8, + 0x00, 0xB1, 0x01, 0x24, + 0x27, 0x48, 0x80, 0x1E, 0x01, 0x78, 0x8C, 0x42, 0x09, 0xD0, 0x04, 0x70, + 0x0C, 0xB1, 0x08, 0x21, + 0x00, 0xE0, 0x10, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x03, 0x20, 0xFB, 0xF7, + 0x42, 0xB9, 0x10, 0xBD, + 0x2D, 0xE9, 0xF0, 0x41, 0x17, 0x48, 0x1A, 0x4E, 0x17, 0x4C, 0x00, 0x68, + 0x34, 0x3E, 0x90, 0xF8, + 0x31, 0x50, 0x90, 0xF8, 0x30, 0x70, 0xB1, 0x69, 0x39, 0xB1, 0x18, 0x48, + 0x84, 0xF8, 0x30, 0x50, + 0xC2, 0x38, 0x6A, 0x00, 0x20, 0x61, 0x11, 0xF0, 0x20, 0xFF, 0xF1, 0x69, + 0x39, 0xB1, 0x13, 0x48, + 0x84, 0xF8, 0x31, 0x70, 0x98, 0x38, 0x7A, 0x00, 0x60, 0x61, 0x11, 0xF0, + 0x16, 0xFF, 0x0D, 0x48, + 0x0D, 0x49, 0x00, 0x78, 0x09, 0x78, 0x08, 0x43, 0x80, 0x06, 0x08, 0xD5, + 0x0B, 0x48, 0x4C, 0x38, + 0xE0, 0x60, 0x6A, 0x00, 0x71, 0x6A, 0xBD, 0xE8, 0xF0, 0x41, 0x11, 0xF0, + 0x06, 0xBF, 0xBD, 0xE8, + 0xF0, 0x81, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xCC, 0x68, 0x10, 0x00, + 0x54, 0x05, 0x10, 0x00, + 0x1C, 0x11, 0x10, 0x00, 0x4C, 0x05, 0x10, 0x00, 0x50, 0x05, 0x10, 0x00, + 0xCC, 0x07, 0x01, 0x20, + 0x1A, 0x05, 0x10, 0x00, 0x48, 0x05, 0x10, 0x00, 0x40, 0x05, 0x10, 0x00, + 0x41, 0x05, 0x10, 0x00, + 0x10, 0xB5, 0x00, 0x24, 0xC1, 0x07, 0x0B, 0xD0, 0x3F, 0x49, 0x03, 0x24, + 0x09, 0x68, 0x91, 0xF8, + 0x50, 0x22, 0xD2, 0x07, 0x03, 0xD1, 0x91, 0xF8, 0x80, 0x12, 0xC9, 0x07, + 0x00, 0xD0, 0x0B, 0x24, + 0x82, 0x07, 0x4F, 0xF0, 0x01, 0x01, 0x03, 0xD5, 0x38, 0x4A, 0x44, 0xF0, + 0x10, 0x04, 0x11, 0x70, + 0x40, 0x06, 0x03, 0xD5, 0x36, 0x48, 0x44, 0xF0, 0x80, 0x04, 0x01, 0x70, + 0x00, 0x2C, 0x12, 0xD0, + 0xFA, 0xF7, 0x96, 0xFF, 0x33, 0x48, 0x01, 0x68, 0x21, 0x43, 0x01, 0x60, + 0xFA, 0xF7, 0x8E, 0xFF, + 0x01, 0x21, 0x05, 0x20, 0x0D, 0xF0, 0xCF, 0xFA, 0xBD, 0xE8, 0x10, 0x40, + 0x4F, 0xF4, 0x80, 0x71, + 0x00, 0x20, 0xFB, 0xF7, 0xC6, 0xB8, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0xF0, + 0xDE, 0xFD, 0x02, 0x21, + 0x01, 0x20, 0xFB, 0xF7, 0xEA, 0xF8, 0x01, 0x20, 0xFB, 0xF7, 0x9B, 0xF9, + 0x38, 0x21, 0x26, 0x48, + 0x11, 0xF0, 0x4C, 0xFF, 0x24, 0x49, 0x01, 0x20, 0x81, 0xF8, 0x2C, 0x00, + 0xFB, 0xF7, 0xAC, 0xF9, + 0x01, 0x21, 0x02, 0x20, 0xFB, 0xF7, 0xAD, 0xF8, 0xBD, 0xE8, 0x10, 0x40, + 0x00, 0xF0, 0x2D, 0xBB, + 0x70, 0xB5, 0x1E, 0x48, 0x1E, 0x4E, 0x05, 0x68, 0x30, 0x68, 0x90, 0xEA, + 0x05, 0x04, 0x1F, 0xD0, + 0x35, 0xB1, 0x40, 0xB1, 0x04, 0xEA, 0x05, 0x00, 0xFF, 0xF7, 0xA2, 0xFF, + 0x35, 0x60, 0x70, 0xBD, + 0xFF, 0xF7, 0xD2, 0xFF, 0xFA, 0xE7, 0x00, 0xF0, 0xB0, 0xFD, 0x02, 0x21, + 0x01, 0x20, 0xFB, 0xF7, + 0xBC, 0xF8, 0x00, 0xF0, 0xD8, 0xF8, 0x00, 0xF0, 0x08, 0xFB, 0x04, 0xEA, + 0x05, 0x00, 0xFF, 0xF7, + 0x8F, 0xFF, 0x00, 0xF0, 0xF1, 0xFA, 0x02, 0x21, 0x01, 0x20, 0xFB, 0xF7, + 0x82, 0xF8, 0xE5, 0xE7, + 0x00, 0x2D, 0xE4, 0xD1, 0x0B, 0x48, 0x00, 0x78, 0x05, 0x28, 0x01, 0xD0, + 0x06, 0x28, 0xDE, 0xD1, + 0x35, 0x60, 0xBD, 0xE8, 0x70, 0x40, 0xAF, 0xE7, 0x4C, 0x07, 0x10, 0x00, + 0x7B, 0x07, 0x10, 0x00, + 0x7C, 0x07, 0x10, 0x00, 0x54, 0x07, 0x10, 0x00, 0xCC, 0x68, 0x10, 0x00, + 0x6C, 0x07, 0x10, 0x00, + 0x44, 0x05, 0x10, 0x00, 0x40, 0x05, 0x10, 0x00, 0x70, 0xB5, 0xFF, 0x49, + 0x00, 0x20, 0x03, 0x46, + 0x09, 0x68, 0x91, 0xF8, 0x40, 0x20, 0xD2, 0x07, 0x38, 0xD0, 0xFC, 0x4A, + 0x15, 0x78, 0x02, 0x2D, + 0x16, 0xD0, 0x04, 0x2D, 0x03, 0xD0, 0x05, 0x2D, 0x0F, 0xD0, 0x06, 0x2D, + 0x0D, 0xD0, 0x91, 0xF8, + 0x41, 0x20, 0xF7, 0x49, 0x0C, 0x68, 0x64, 0x1C, 0x0C, 0x60, 0x94, 0x42, + 0x26, 0xDD, 0xF5, 0x4A, + 0x00, 0x20, 0x14, 0x78, 0x64, 0xB1, 0x08, 0x60, 0x0C, 0xE0, 0x91, 0xF8, + 0x43, 0x20, 0xF0, 0xE7, + 0x91, 0xF8, 0x42, 0x20, 0x91, 0xF8, 0x90, 0x10, 0xC9, 0x06, 0xEA, 0xD5, + 0x01, 0x23, 0xE8, 0xE7, + 0x13, 0xB1, 0x01, 0x20, 0x10, 0x70, 0x00, 0xE0, 0x08, 0x60, 0x05, 0x2D, + 0x0F, 0xD0, 0x00, 0xF0, + 0x11, 0xF9, 0x04, 0x46, 0x00, 0xF0, 0x14, 0xF9, 0x04, 0x43, 0x00, 0xF0, + 0x1F, 0xF9, 0x04, 0x43, + 0x00, 0xF0, 0x2B, 0xF9, 0x04, 0x43, 0x00, 0xF0, 0x35, 0xF9, 0x20, 0x43, + 0x70, 0xBD, 0x01, 0x20, + 0x70, 0xBD, 0x10, 0xB5, 0x01, 0x46, 0x34, 0x22, 0xDF, 0x48, 0x11, 0xF0, + 0x53, 0xFE, 0x01, 0x21, + 0xBD, 0xE8, 0x10, 0x40, 0x08, 0x46, 0xFB, 0xF7, 0x14, 0xB8, 0x2D, 0xE9, + 0xFF, 0x41, 0x80, 0x46, + 0xD6, 0x48, 0x00, 0x78, 0x02, 0x28, 0x24, 0xD0, 0x03, 0x28, 0x1E, 0xD0, + 0x04, 0x24, 0xD7, 0x4D, + 0xD7, 0x4E, 0x01, 0x27, 0x05, 0x28, 0x20, 0xD0, 0x06, 0x28, 0x68, 0x46, + 0x30, 0xD0, 0x00, 0xF0, + 0xB5, 0xF9, 0xD4, 0x48, 0x00, 0x90, 0xCC, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0xB0, 0x00, 0xC0, 0x07, + 0x01, 0xD0, 0x8D, 0xF8, 0x0D, 0x80, 0x68, 0x46, 0x11, 0xF0, 0x71, 0xFA, + 0xCE, 0x49, 0xCF, 0x4A, + 0xC9, 0x78, 0x11, 0x70, 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x81, 0x68, 0x46, + 0x00, 0xF0, 0x4A, 0xF9, + 0xE7, 0xE7, 0x68, 0x46, 0x00, 0xF0, 0x05, 0xF9, 0xE3, 0xE7, 0x68, 0x46, + 0x11, 0xF0, 0x3A, 0xFA, + 0xFF, 0xF7, 0x7A, 0xFF, 0x40, 0x21, 0xC2, 0x07, 0x01, 0xD0, 0x8D, 0xF8, + 0x04, 0x40, 0xC2, 0x06, + 0x01, 0xD5, 0x8D, 0xF8, 0x06, 0x70, 0x8D, 0xF8, 0x08, 0x70, 0x28, 0x60, + 0x31, 0x60, 0xD0, 0xE7, + 0x00, 0x27, 0x11, 0xF0, 0x27, 0xFA, 0x8D, 0xF8, 0x04, 0x40, 0x01, 0x20, + 0x2F, 0x60, 0x30, 0x60, + 0xC7, 0xE7, 0x10, 0xB5, 0x00, 0xF0, 0xE1, 0xFC, 0x02, 0x21, 0xBD, 0xE8, + 0x10, 0x40, 0x01, 0x20, + 0xFA, 0xF7, 0xBF, 0xBF, 0x10, 0xB5, 0x00, 0xF0, 0xDD, 0xFC, 0x20, 0x21, + 0xBD, 0xE8, 0x10, 0x40, + 0x01, 0x20, 0xFA, 0xF7, 0xB6, 0xBF, 0xAA, 0x49, 0x00, 0x20, 0x08, 0x60, + 0x70, 0x47, 0xA8, 0x49, + 0x00, 0x20, 0x08, 0x60, 0x70, 0x47, 0xF8, 0xB5, 0x00, 0x24, 0x20, 0x46, + 0xFB, 0xF7, 0x89, 0xF8, + 0x00, 0xF0, 0x32, 0xFA, 0xA1, 0x4E, 0x30, 0x78, 0x00, 0xF0, 0x93, 0xF9, + 0xAF, 0xF2, 0x4D, 0x01, + 0x00, 0xF0, 0xB3, 0xFC, 0x9C, 0x4F, 0xA6, 0x4D, 0x38, 0x68, 0x90, 0xF8, + 0xB0, 0x00, 0xC1, 0x07, + 0x09, 0xD0, 0x01, 0x24, 0xC0, 0xF3, 0xC1, 0x01, 0x02, 0x29, 0x00, 0xD1, + 0x00, 0x24, 0x80, 0x07, + 0x01, 0xD5, 0x00, 0x20, 0x28, 0x70, 0x20, 0x46, 0xFF, 0xF7, 0x77, 0xFF, + 0x96, 0x4C, 0x01, 0x28, + 0x0D, 0xD1, 0x01, 0x21, 0x6B, 0x46, 0x00, 0x22, 0x08, 0x46, 0xFA, 0xF7, + 0xCB, 0xFF, 0x01, 0x21, + 0x08, 0x46, 0xFA, 0xF7, 0xAA, 0xFF, 0x20, 0x78, 0x90, 0xB1, 0x0C, 0xF0, + 0x8E, 0xFF, 0x00, 0x20, + 0xFB, 0xF7, 0x72, 0xF8, 0x38, 0x68, 0x90, 0xF8, 0xB0, 0x10, 0xCA, 0x07, + 0x51, 0xD0, 0x89, 0x07, + 0x4F, 0xD5, 0x8D, 0x49, 0x49, 0x78, 0x00, 0x29, 0x4B, 0xD1, 0x29, 0x78, + 0x19, 0xB1, 0x28, 0xE0, + 0xFF, 0xF7, 0xF6, 0xFD, 0xEB, 0xE7, 0x32, 0x78, 0x8A, 0x49, 0x02, 0x2A, + 0x02, 0xD1, 0x83, 0x4A, + 0x12, 0x68, 0x2A, 0xB1, 0x09, 0x78, 0x49, 0x06, 0x0B, 0xD5, 0x90, 0xF8, + 0xC1, 0x00, 0x0A, 0xE0, + 0x09, 0x78, 0x49, 0x06, 0x02, 0xD5, 0x90, 0xF8, 0xC2, 0x00, 0x04, 0xE0, + 0x90, 0xF8, 0xBC, 0x00, + 0x01, 0xE0, 0x90, 0xF8, 0xBB, 0x00, 0xAF, 0xF2, 0xE3, 0x01, 0x00, 0xF0, + 0x68, 0xFC, 0x6B, 0x46, + 0x00, 0x22, 0x20, 0x21, 0x01, 0x20, 0xFA, 0xF7, 0x8D, 0xFF, 0x20, 0x21, + 0x01, 0x20, 0xFA, 0xF7, + 0x6C, 0xFF, 0x28, 0x78, 0x00, 0x28, 0x1C, 0xD1, 0xFB, 0xF7, 0x1B, 0xF8, + 0x00, 0x20, 0xFF, 0xF7, + 0x24, 0xFF, 0x01, 0x28, 0x0D, 0xD1, 0x01, 0x21, 0x6B, 0x46, 0x00, 0x22, + 0x08, 0x46, 0xFA, 0xF7, + 0x79, 0xFF, 0x01, 0x21, 0x08, 0x46, 0xFA, 0xF7, 0x58, 0xFF, 0x20, 0x78, + 0x30, 0xB1, 0x0C, 0xF0, + 0x3C, 0xFF, 0xBD, 0xE8, 0xF8, 0x40, 0x00, 0x20, 0xFB, 0xF7, 0x1E, 0xB8, + 0xFF, 0xF7, 0xB0, 0xFD, + 0xF7, 0xE7, 0xF8, 0xBD, 0x67, 0x48, 0x00, 0x78, 0xC0, 0x07, 0x00, 0xD0, + 0x01, 0x20, 0x70, 0x47, + 0x64, 0x48, 0x00, 0x78, 0xC0, 0x07, 0x07, 0xD0, 0x57, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x50, 0x02, + 0xC0, 0x07, 0x01, 0xD0, 0x10, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, + 0x5D, 0x48, 0x00, 0x78, + 0xC1, 0x07, 0x51, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x80, 0x02, 0x03, 0xD0, + 0xC1, 0x07, 0x01, 0xD0, + 0x10, 0x20, 0x70, 0x47, 0x00, 0xF0, 0x01, 0x00, 0x70, 0x47, 0x56, 0x48, + 0x00, 0x78, 0x80, 0x07, + 0x06, 0xD5, 0x49, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x61, 0x04, 0x08, 0xB1, + 0x02, 0x20, 0x70, 0x47, + 0x00, 0x20, 0x70, 0x47, 0x4F, 0x48, 0x00, 0x78, 0x40, 0x06, 0x08, 0xD5, + 0x42, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x2F, 0x0A, 0xC0, 0x07, 0x02, 0xD0, 0x4F, 0xF4, 0x00, 0x70, + 0x70, 0x47, 0x00, 0x20, + 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0x06, 0x46, 0x00, 0x27, 0x11, 0xF0, + 0x33, 0xF9, 0xFF, 0xF7, + 0x73, 0xFE, 0x05, 0x46, 0x43, 0x48, 0x00, 0x78, 0xC0, 0x07, 0x00, 0xD0, + 0x40, 0x27, 0xFF, 0xF7, + 0xD4, 0xFF, 0x40, 0xEA, 0x07, 0x04, 0x6D, 0xB1, 0x33, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x90, 0x00, + 0x00, 0x07, 0x07, 0xD5, 0x00, 0xF0, 0xE4, 0xF8, 0x40, 0xEA, 0x04, 0x07, + 0x00, 0xF0, 0xEE, 0xF8, + 0x40, 0xEA, 0x07, 0x04, 0x45, 0xEA, 0x04, 0x07, 0xF8, 0x07, 0x02, 0xD0, + 0x00, 0xF0, 0xF4, 0xF8, + 0x30, 0x71, 0x61, 0x07, 0x4F, 0xF0, 0x01, 0x00, 0x00, 0xD5, 0x70, 0x71, + 0xE9, 0x06, 0x00, 0xD5, + 0xB0, 0x71, 0x61, 0x06, 0x00, 0xD5, 0x30, 0x72, 0xA1, 0x06, 0x00, 0xD5, + 0xF0, 0x71, 0xB9, 0x07, + 0x00, 0xD5, 0x70, 0x72, 0xA9, 0x05, 0x00, 0xD5, 0xB0, 0x72, 0x24, 0x48, + 0x05, 0x60, 0x24, 0x48, + 0x04, 0x60, 0xB0, 0xE6, 0x2D, 0xE9, 0xF0, 0x41, 0x05, 0x46, 0x11, 0xF0, + 0xF3, 0xF8, 0xFF, 0xF7, + 0x33, 0xFE, 0x07, 0x46, 0xFF, 0xF7, 0x76, 0xFF, 0x04, 0x46, 0xFF, 0xF7, + 0x79, 0xFF, 0x04, 0x43, + 0xFF, 0xF7, 0x84, 0xFF, 0x04, 0x43, 0x00, 0xF0, 0xAB, 0xF8, 0x04, 0x43, + 0xFF, 0xF7, 0x8D, 0xFF, + 0x04, 0x43, 0xFF, 0xF7, 0x97, 0xFF, 0x04, 0x43, 0x00, 0xF0, 0xB0, 0xF8, + 0x40, 0xEA, 0x04, 0x06, + 0x47, 0xEA, 0x06, 0x04, 0xE0, 0x07, 0x02, 0xD0, 0x00, 0xF0, 0xB6, 0xF8, + 0x28, 0x71, 0x71, 0x07, + 0x4F, 0xF0, 0x01, 0x00, 0x00, 0xD5, 0x68, 0x71, 0xE1, 0x06, 0x00, 0xD5, + 0xA8, 0x71, 0xB1, 0x06, + 0x00, 0xD5, 0xE8, 0x71, 0xA1, 0x07, 0x00, 0xD5, 0x68, 0x72, 0xA1, 0x05, + 0x00, 0xD5, 0xA8, 0x72, + 0x06, 0x48, 0x07, 0x60, 0x06, 0x48, 0x17, 0xE0, 0x4C, 0x07, 0x10, 0x00, + 0x40, 0x05, 0x10, 0x00, + 0x24, 0x05, 0x10, 0x00, 0x41, 0x05, 0x10, 0x00, 0xE8, 0x10, 0x10, 0x00, + 0x50, 0x05, 0x10, 0x00, + 0x4C, 0x05, 0x10, 0x00, 0xE3, 0x54, 0x00, 0x00, 0x74, 0x07, 0x10, 0x00, + 0x54, 0x05, 0x10, 0x00, + 0x78, 0x07, 0x10, 0x00, 0x44, 0x05, 0x10, 0x00, 0x06, 0x60, 0x5C, 0xE6, + 0x2D, 0xE9, 0xF0, 0x41, + 0x05, 0x46, 0x11, 0xF0, 0x9F, 0xF8, 0xFF, 0xF7, 0xDF, 0xFD, 0x06, 0x46, + 0xFF, 0xF7, 0x22, 0xFF, + 0x04, 0x46, 0xFF, 0xF7, 0x25, 0xFF, 0x04, 0x43, 0xFF, 0xF7, 0x30, 0xFF, + 0x04, 0x43, 0x00, 0xF0, + 0x57, 0xF8, 0x04, 0x43, 0xFF, 0xF7, 0x39, 0xFF, 0x04, 0x43, 0xFF, 0xF7, + 0x43, 0xFF, 0x04, 0x43, + 0x00, 0xF0, 0x5C, 0xF8, 0x40, 0xEA, 0x04, 0x07, 0x46, 0xEA, 0x07, 0x04, + 0xE0, 0x07, 0x02, 0xD0, + 0x00, 0xF0, 0x62, 0xF8, 0x28, 0x71, 0x61, 0x07, 0x4F, 0xF0, 0x01, 0x00, + 0x00, 0xD5, 0x68, 0x71, + 0xE1, 0x06, 0x00, 0xD5, 0xA8, 0x71, 0xB9, 0x06, 0x00, 0xD5, 0xE8, 0x71, + 0xA1, 0x07, 0x00, 0xD5, + 0x68, 0x72, 0xA1, 0x05, 0x00, 0xD5, 0xA8, 0x72, 0x2E, 0x48, 0x06, 0x60, + 0x2E, 0x48, 0x07, 0x60, + 0x21, 0xE6, 0x38, 0xB5, 0x2D, 0x49, 0x80, 0x1E, 0x05, 0x28, 0x09, 0x68, + 0x13, 0xD2, 0xDF, 0xE8, + 0x00, 0xF0, 0x03, 0x06, 0x09, 0x0C, 0x0F, 0x00, 0x91, 0xF8, 0x73, 0x40, + 0x0C, 0xE0, 0x91, 0xF8, + 0x72, 0x40, 0x09, 0xE0, 0x91, 0xF8, 0x71, 0x40, 0x06, 0xE0, 0x91, 0xF8, + 0x74, 0x40, 0x03, 0xE0, + 0x91, 0xF8, 0x75, 0x40, 0x00, 0xE0, 0x01, 0x24, 0x00, 0x25, 0x0C, 0xF0, + 0x53, 0xFA, 0x00, 0xB1, + 0x01, 0x25, 0x69, 0x46, 0x03, 0x20, 0xFA, 0xF7, 0x26, 0xFE, 0x00, 0x98, + 0x00, 0xB9, 0x1D, 0xB1, + 0x14, 0x2C, 0x01, 0xD2, 0x14, 0x24, 0x01, 0xE0, 0x04, 0xB9, 0x01, 0x24, + 0x20, 0x46, 0x38, 0xBD, + 0x17, 0x48, 0x00, 0x78, 0xC0, 0x07, 0x07, 0xD0, 0x14, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0xF0, 0x01, + 0xC0, 0x07, 0x01, 0xD0, 0x04, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, + 0x10, 0x48, 0x00, 0x78, + 0xC0, 0x07, 0x07, 0xD0, 0x0D, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x10, 0x02, + 0xC0, 0x07, 0x01, 0xD0, + 0x20, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x08, 0x49, 0x01, 0x20, + 0x09, 0x68, 0x91, 0xF8, + 0xE7, 0x10, 0x09, 0x06, 0x03, 0xD5, 0x07, 0x48, 0x40, 0x78, 0x08, 0xB1, + 0x03, 0x20, 0x70, 0x47, + 0x02, 0x20, 0x70, 0x47, 0x50, 0x05, 0x10, 0x00, 0x4C, 0x05, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0x44, 0x05, 0x10, 0x00, 0x74, 0x07, 0x10, 0x00, 0x10, 0xB5, 0x00, 0xF0, + 0x8B, 0xF9, 0x00, 0xF0, + 0x00, 0xFA, 0x5B, 0x49, 0x00, 0x20, 0x48, 0x60, 0x5A, 0x49, 0x02, 0x20, + 0x08, 0x70, 0x10, 0xBD, + 0x10, 0xB5, 0x00, 0xF0, 0x7F, 0xF9, 0x00, 0xF0, 0xF4, 0xF9, 0x55, 0x49, + 0x00, 0x20, 0x48, 0x60, + 0x54, 0x49, 0x03, 0x20, 0x08, 0x70, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0xF0, + 0x73, 0xF9, 0x00, 0xF0, + 0xE8, 0xF9, 0x4F, 0x49, 0x00, 0x20, 0x48, 0x60, 0x4E, 0x49, 0x04, 0x20, + 0x08, 0x70, 0x4E, 0x49, + 0x01, 0x20, 0x08, 0x70, 0x4D, 0x49, 0x08, 0x70, 0x10, 0xBD, 0x49, 0x49, + 0x00, 0x20, 0x48, 0x60, + 0x70, 0x47, 0x47, 0x49, 0x00, 0x20, 0x48, 0x60, 0x70, 0x47, 0x45, 0x49, + 0x00, 0x20, 0x48, 0x60, + 0x44, 0x49, 0x01, 0x20, 0x08, 0x70, 0x70, 0x47, 0x70, 0xB5, 0x42, 0x4D, + 0x00, 0x26, 0x40, 0x4C, + 0x28, 0x78, 0x80, 0x1E, 0x04, 0x28, 0x10, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, + 0x30, 0x1F, 0x02, 0x3E, + 0x00, 0xF0, 0x45, 0xF8, 0x01, 0x28, 0x07, 0xD0, 0x60, 0x68, 0x40, 0x1C, + 0x60, 0x60, 0x00, 0xF0, + 0x46, 0xF8, 0x01, 0x28, 0x02, 0xD0, 0x0B, 0xE0, 0x66, 0x60, 0x70, 0xBD, + 0x38, 0x48, 0x61, 0x68, + 0x00, 0x68, 0x90, 0xF8, 0x77, 0x00, 0x88, 0x42, 0x02, 0xD2, 0xBD, 0xE8, + 0x70, 0x40, 0xAF, 0xE7, + 0x00, 0xF0, 0x47, 0xF8, 0x01, 0x28, 0x0E, 0xD0, 0x70, 0xBD, 0x00, 0xF0, + 0x28, 0xF8, 0x01, 0x28, + 0x17, 0xD0, 0x60, 0x68, 0x40, 0x1C, 0x60, 0x60, 0x00, 0xF0, 0x3B, 0xF8, + 0x01, 0x28, 0x02, 0xD0, + 0x00, 0xF0, 0x25, 0xF8, 0x0B, 0xE0, 0xBD, 0xE8, 0x70, 0x40, 0x8D, 0xE7, + 0x00, 0xF0, 0x17, 0xF8, + 0x01, 0x28, 0x06, 0xD0, 0x60, 0x68, 0x40, 0x1C, 0x60, 0x60, 0x00, 0xF0, + 0x22, 0xF8, 0x01, 0x28, + 0xE2, 0xD0, 0xBD, 0xE8, 0x70, 0x40, 0x97, 0xE7, 0x00, 0xF0, 0x09, 0xF9, + 0x08, 0xB1, 0x21, 0x78, + 0x09, 0xB1, 0x20, 0x70, 0x70, 0xBD, 0x20, 0x70, 0x06, 0x20, 0x28, 0x70, + 0x70, 0xBD, 0x10, 0xB5, + 0x00, 0xF0, 0xFD, 0xF8, 0x04, 0x46, 0x0B, 0xF0, 0x43, 0xFD, 0x20, 0x43, + 0x10, 0xBD, 0x18, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x70, 0x00, 0x80, 0x07, 0x01, 0xD5, 0x01, 0x20, + 0x70, 0x47, 0x00, 0x20, + 0x70, 0x47, 0x13, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x70, 0x00, 0xC0, 0x07, + 0x00, 0xD0, 0x01, 0x20, + 0x70, 0x47, 0x10, 0xB5, 0xFF, 0xF7, 0xF5, 0xFF, 0x01, 0x28, 0x0F, 0xD1, + 0x00, 0xF0, 0x5F, 0xF9, + 0x60, 0xB9, 0x0B, 0x48, 0x06, 0x49, 0x00, 0x68, 0x49, 0x68, 0x90, 0xF8, + 0x78, 0x00, 0x00, 0xEB, + 0x80, 0x00, 0xB1, 0xEB, 0x40, 0x0F, 0x01, 0xD9, 0x01, 0x20, 0x10, 0xBD, + 0x00, 0x20, 0x10, 0xBD, + 0x28, 0x05, 0x10, 0x00, 0x40, 0x05, 0x10, 0x00, 0x79, 0x07, 0x10, 0x00, + 0x7A, 0x07, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0x8E, 0x4C, 0x07, 0x46, + 0x0E, 0x46, 0x20, 0x68, + 0x00, 0x25, 0x90, 0xF8, 0x98, 0x20, 0x8C, 0x48, 0x0E, 0xF0, 0xBD, 0xFA, + 0x02, 0x00, 0x8B, 0x48, + 0x29, 0x46, 0x34, 0xD0, 0x02, 0x78, 0x01, 0x25, 0x52, 0x1C, 0xD2, 0xB2, + 0x02, 0x70, 0x23, 0x68, + 0x93, 0xF8, 0x99, 0x30, 0x93, 0x42, 0x2B, 0xD2, 0x01, 0x70, 0x83, 0x48, + 0x76, 0x00, 0x32, 0x46, + 0x39, 0x46, 0x54, 0x38, 0x11, 0xF0, 0xB9, 0xFA, 0x7F, 0x48, 0x32, 0x46, + 0x39, 0x46, 0x2A, 0x38, + 0x11, 0xF0, 0xB3, 0xFA, 0x20, 0x68, 0x03, 0x26, 0x90, 0xF8, 0x50, 0x12, + 0xC9, 0x07, 0x03, 0xD1, + 0x90, 0xF8, 0x80, 0x02, 0xC0, 0x07, 0x00, 0xD0, 0x0B, 0x26, 0xFA, 0xF7, + 0x71, 0xFB, 0x78, 0x48, + 0x01, 0x68, 0x31, 0x43, 0x01, 0x60, 0xFA, 0xF7, 0x69, 0xFB, 0x20, 0x21, + 0x05, 0x20, 0x0C, 0xF0, + 0xAA, 0xFE, 0x4F, 0xF4, 0x80, 0x71, 0x00, 0x20, 0xFA, 0xF7, 0xA3, 0xFC, + 0x00, 0xE0, 0x01, 0x70, + 0x28, 0x46, 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xF0, 0x47, 0x88, 0x46, + 0x00, 0x28, 0x6B, 0xD0, + 0xDF, 0xF8, 0xB0, 0xA1, 0x00, 0x21, 0x69, 0x4C, 0x9A, 0xF8, 0x00, 0x20, + 0x89, 0x46, 0x02, 0x2A, + 0x03, 0xD0, 0x03, 0x2A, 0x01, 0xD0, 0x05, 0x2A, 0x5D, 0xD1, 0x00, 0x21, + 0xB8, 0xF1, 0x00, 0x0F, + 0x00, 0xD0, 0x01, 0x21, 0xA2, 0x88, 0x00, 0xEB, 0x41, 0x00, 0x52, 0x1A, + 0x15, 0xB2, 0x07, 0x46, + 0xA2, 0x78, 0x29, 0x46, 0x00, 0xF0, 0x71, 0xF8, 0x5A, 0x4E, 0xA0, 0x70, + 0x30, 0x68, 0x90, 0xF8, + 0x90, 0x00, 0x80, 0x07, 0x04, 0xD5, 0x38, 0x46, 0x29, 0x46, 0xFF, 0xF7, + 0x8B, 0xFF, 0x81, 0x46, + 0x00, 0x22, 0x01, 0x21, 0xB8, 0xF1, 0x00, 0x0F, 0x1A, 0xD0, 0x00, 0x27, + 0xDF, 0xF8, 0x48, 0xC1, + 0x38, 0x46, 0x36, 0x68, 0x10, 0xE0, 0x00, 0xBF, 0x3C, 0xF9, 0x10, 0x30, + 0x00, 0x2B, 0x00, 0xDA, + 0x5B, 0x42, 0xB6, 0xF8, 0x92, 0x80, 0x43, 0x45, 0x04, 0xDD, 0x96, 0xF8, + 0x91, 0x30, 0x7F, 0x1C, + 0xBB, 0x42, 0x1B, 0xDD, 0x40, 0x1C, 0xC0, 0xB2, 0xA8, 0x42, 0xED, 0xDB, + 0x11, 0x46, 0x22, 0xE0, + 0x00, 0x23, 0x45, 0x4F, 0x18, 0x46, 0x36, 0x68, 0x0D, 0xE0, 0x00, 0xBF, + 0x37, 0xF9, 0x10, 0xC0, + 0xB6, 0xF8, 0x92, 0x80, 0xC4, 0x45, 0x04, 0xDD, 0x96, 0xF8, 0x91, 0xC0, + 0x5B, 0x1C, 0x9C, 0x45, + 0x04, 0xDD, 0x40, 0x1C, 0xC0, 0xB2, 0xA8, 0x42, 0xF0, 0xDB, 0xE7, 0xE7, + 0x9A, 0xF8, 0x00, 0x00, + 0x02, 0x28, 0x0B, 0xD0, 0x03, 0x28, 0x09, 0xD0, 0x05, 0x28, 0x04, 0xD1, + 0x60, 0x78, 0x10, 0xB9, + 0xB9, 0xF1, 0x00, 0x0F, 0x02, 0xD0, 0x61, 0x70, 0xBD, 0xE8, 0xF0, 0x87, + 0x61, 0x70, 0x00, 0xF0, + 0x44, 0xF9, 0xBD, 0xE8, 0xF0, 0x47, 0x02, 0x21, 0x01, 0x20, 0xFA, 0xF7, + 0x22, 0xBC, 0x2F, 0x48, + 0x40, 0x78, 0x70, 0x47, 0x2D, 0x48, 0x00, 0x21, 0x01, 0x22, 0x01, 0x70, + 0x82, 0x70, 0x29, 0x4A, + 0x12, 0x68, 0x92, 0xF8, 0x31, 0x20, 0x82, 0x80, 0x2A, 0x4A, 0x12, 0x78, + 0x05, 0x2A, 0x02, 0xD0, + 0x06, 0x2A, 0x00, 0xD0, 0x41, 0x70, 0x70, 0x47, 0xEC, 0xE7, 0x2D, 0xE9, + 0xFC, 0x41, 0x80, 0x46, + 0x22, 0x48, 0x14, 0x46, 0x0D, 0x46, 0x40, 0x78, 0x16, 0x46, 0x40, 0xB9, + 0x1E, 0x48, 0x0A, 0x46, + 0x7F, 0x23, 0x41, 0x46, 0x54, 0x38, 0x00, 0x94, 0x0E, 0xF0, 0x22, 0xFA, + 0x00, 0x26, 0x19, 0x4F, + 0x38, 0x68, 0x90, 0xF8, 0x90, 0x10, 0xC9, 0x07, 0x00, 0xD0, 0xEC, 0xB1, + 0x16, 0x48, 0x6A, 0x00, + 0x41, 0x46, 0x2A, 0x38, 0x11, 0xF0, 0xE1, 0xF9, 0x13, 0x4A, 0x2B, 0x46, + 0x54, 0x3A, 0x02, 0xF1, + 0x2A, 0x01, 0x11, 0x48, 0x0E, 0xF0, 0xE5, 0xF9, 0x38, 0x68, 0x90, 0xF8, + 0x90, 0x10, 0x49, 0x07, + 0x07, 0xD5, 0x90, 0xF8, 0x9A, 0x30, 0x23, 0xB1, 0x0B, 0x49, 0x2A, 0x46, + 0x08, 0x46, 0x0E, 0xF0, + 0x18, 0xFA, 0x30, 0x46, 0xBD, 0xE8, 0xFC, 0x81, 0xB0, 0xF9, 0x96, 0x10, + 0xCD, 0xE9, 0x00, 0x15, + 0x05, 0x4A, 0xB0, 0xF9, 0x94, 0x30, 0x54, 0x3A, 0x41, 0x46, 0x02, 0xF1, + 0x2A, 0x00, 0x0E, 0xF0, + 0x4F, 0xF9, 0xD9, 0xE7, 0x4C, 0x07, 0x10, 0x00, 0x50, 0x09, 0x01, 0x20, + 0x30, 0x05, 0x10, 0x00, + 0x54, 0x07, 0x10, 0x00, 0x40, 0x05, 0x10, 0x00, 0x70, 0xB5, 0x00, 0x28, + 0x04, 0x9E, 0x0D, 0xD0, + 0x00, 0x24, 0x06, 0xE0, 0x30, 0xF9, 0x11, 0x50, 0x9D, 0x42, 0x01, 0xDD, + 0x95, 0x42, 0x00, 0xDB, + 0x64, 0x1C, 0x49, 0x1E, 0xF6, 0xD2, 0xB4, 0x42, 0x01, 0xDD, 0x01, 0x20, + 0x70, 0xBD, 0x00, 0x20, + 0x70, 0xBD, 0x3F, 0x48, 0x00, 0x21, 0x01, 0x70, 0x41, 0x60, 0x70, 0x47, + 0xF9, 0xE7, 0x3C, 0x48, + 0x00, 0x78, 0x70, 0x47, 0x2D, 0xE9, 0xF3, 0x4F, 0xDF, 0xF8, 0xE8, 0xA0, + 0x84, 0x46, 0x4F, 0xF0, + 0x00, 0x08, 0xDA, 0xF8, 0x00, 0x00, 0xDF, 0xF8, 0xD8, 0xB0, 0x81, 0xB0, + 0x90, 0xF8, 0x80, 0x10, + 0x47, 0x46, 0xC9, 0x07, 0xC1, 0x46, 0x2B, 0xD0, 0x33, 0x49, 0x09, 0x78, + 0x03, 0x29, 0x2D, 0xD0, + 0x04, 0x29, 0x2B, 0xD0, 0x05, 0x29, 0x36, 0xD1, 0xB0, 0xF8, 0x88, 0x60, + 0xB0, 0xF8, 0x8A, 0x50, + 0x90, 0xF8, 0x87, 0x40, 0xBC, 0xF1, 0x00, 0x0F, 0x08, 0xD0, 0x00, 0x94, + 0x90, 0xF8, 0x31, 0x10, + 0x2B, 0xB2, 0x32, 0xB2, 0x60, 0x46, 0xFF, 0xF7, 0xB7, 0xFF, 0x80, 0x46, + 0x02, 0x98, 0x50, 0xB1, + 0x00, 0x94, 0xDA, 0xF8, 0x00, 0x00, 0x2B, 0xB2, 0x32, 0xB2, 0x90, 0xF8, + 0x30, 0x10, 0x02, 0x98, + 0xFF, 0xF7, 0xAA, 0xFF, 0x07, 0x46, 0xB8, 0xF1, 0x01, 0x0F, 0x0E, 0xD0, + 0x01, 0x2F, 0x0C, 0xD0, + 0x9B, 0xF8, 0x00, 0x10, 0x58, 0x46, 0x01, 0x29, 0x1D, 0xD0, 0x0A, 0xE0, + 0xB0, 0xF8, 0x82, 0x60, + 0xB0, 0xF8, 0x84, 0x50, 0x90, 0xF8, 0x86, 0x40, 0xD4, 0xE7, 0x9B, 0xF8, + 0x00, 0x10, 0x58, 0x46, + 0x19, 0xB1, 0xCB, 0xF8, 0x04, 0x90, 0xBD, 0xE8, 0xFE, 0x8F, 0x41, 0x68, + 0x49, 0x1C, 0x41, 0x60, + 0xDA, 0xF8, 0x00, 0x20, 0x92, 0xF8, 0x81, 0x20, 0x8A, 0x42, 0xF4, 0xDA, + 0x01, 0x21, 0x01, 0x70, + 0xCB, 0xF8, 0x04, 0x90, 0x0D, 0xE0, 0x41, 0x68, 0x49, 0x1C, 0x41, 0x60, + 0xDA, 0xF8, 0x00, 0x20, + 0x92, 0xF8, 0x81, 0x20, 0x8A, 0x42, 0xE6, 0xDA, 0x80, 0xF8, 0x00, 0x90, + 0x00, 0x21, 0xCB, 0xF8, + 0x04, 0x90, 0x03, 0xB0, 0x07, 0x20, 0xBD, 0xE8, 0xF0, 0x4F, 0x0C, 0xF0, + 0x2C, 0xBD, 0x00, 0x00, + 0x38, 0x05, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x40, 0x05, 0x10, 0x00, + 0x22, 0x49, 0x08, 0xB5, + 0x00, 0x20, 0x48, 0x60, 0x01, 0x22, 0x88, 0x60, 0x0A, 0x70, 0x48, 0x70, + 0x1F, 0x49, 0x08, 0x70, + 0x1F, 0x49, 0x08, 0x70, 0xFF, 0xF7, 0x08, 0xFF, 0xFF, 0xF7, 0x70, 0xFF, + 0xFF, 0xF7, 0x5F, 0xFB, + 0xFF, 0xF7, 0x8F, 0xFD, 0x6B, 0x46, 0x00, 0x22, 0x1E, 0x21, 0x01, 0x20, + 0xFA, 0xF7, 0x52, 0xFB, + 0x00, 0x98, 0x41, 0x07, 0x03, 0xD5, 0xFF, 0xF7, 0x5B, 0xFA, 0x04, 0x21, + 0x08, 0xE0, 0x01, 0x07, + 0x03, 0xD5, 0xFF, 0xF7, 0x73, 0xF8, 0x08, 0x21, 0x02, 0xE0, 0xC1, 0x06, + 0x04, 0xD5, 0x10, 0x21, + 0x01, 0x20, 0xFA, 0xF7, 0x22, 0xFB, 0xE5, 0xE7, 0x80, 0x07, 0xE3, 0xD5, + 0x02, 0x21, 0x01, 0x20, + 0xFA, 0xF7, 0x1B, 0xFB, 0xFF, 0xF7, 0x3F, 0xFB, 0xDC, 0xE7, 0x00, 0xEB, + 0x80, 0x00, 0x4F, 0xF6, + 0xFF, 0x72, 0x02, 0xEA, 0x40, 0x00, 0xFB, 0xF7, 0xAA, 0xBC, 0xFB, 0xF7, + 0xB8, 0xBC, 0x80, 0xB2, + 0xFB, 0xF7, 0xE9, 0xBB, 0xFB, 0xF7, 0xFB, 0xBB, 0x40, 0x05, 0x10, 0x00, + 0x78, 0x07, 0x10, 0x00, + 0x7D, 0x07, 0x10, 0x00, 0x01, 0xF0, 0x41, 0xBA, 0x5E, 0x48, 0x5F, 0x49, + 0x00, 0x7E, 0x09, 0x7E, + 0xC8, 0x42, 0x09, 0xD1, 0x5D, 0x48, 0x00, 0x78, 0x80, 0x06, 0x05, 0xD5, + 0x01, 0x23, 0x5C, 0x4A, + 0x59, 0x49, 0x58, 0x48, 0x00, 0xF0, 0x00, 0xBD, 0x70, 0x47, 0x3C, 0xB5, + 0x00, 0x23, 0x00, 0x93, + 0x01, 0x93, 0x6B, 0x46, 0x07, 0xE0, 0x44, 0x18, 0x64, 0x78, 0x14, 0xB1, + 0x1D, 0x5D, 0x6D, 0x1C, + 0x1D, 0x55, 0x49, 0x1C, 0xC9, 0xB2, 0x91, 0x42, 0xF5, 0xD9, 0x00, 0x20, + 0x01, 0x21, 0x1C, 0x5C, + 0x5A, 0x5C, 0xA2, 0x42, 0x00, 0xD9, 0x08, 0x46, 0x49, 0x1C, 0xC9, 0xB2, + 0x06, 0x29, 0xF6, 0xD3, + 0x3C, 0xBD, 0x70, 0xB5, 0x04, 0x46, 0x00, 0x20, 0x08, 0x70, 0x0E, 0x46, + 0x10, 0x70, 0x45, 0x48, + 0x45, 0x49, 0x15, 0x46, 0x00, 0x7E, 0x09, 0x7E, 0xC8, 0x42, 0x0B, 0xD0, + 0xE2, 0x78, 0xA1, 0x78, + 0x44, 0x48, 0xFF, 0xF7, 0xD2, 0xFF, 0x30, 0x70, 0x62, 0x78, 0x21, 0x78, + 0x42, 0x48, 0xFF, 0xF7, + 0xCC, 0xFF, 0x28, 0x70, 0x70, 0xBD, 0x70, 0xB5, 0x00, 0x24, 0x01, 0x23, + 0x05, 0x7E, 0x08, 0xE0, + 0xC6, 0x18, 0x96, 0xF9, 0x12, 0x60, 0x8E, 0x42, 0x02, 0xDB, 0x96, 0x42, + 0x00, 0xDC, 0x64, 0x1C, + 0x5B, 0x1C, 0x9D, 0x42, 0xF4, 0xD2, 0x01, 0x2C, 0x01, 0xDC, 0x01, 0x20, + 0x70, 0xBD, 0x00, 0x20, + 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x43, 0x99, 0x46, 0x00, 0x23, 0x1F, 0x46, + 0x47, 0xF6, 0xFF, 0x76, + 0x4F, 0xF0, 0xFF, 0x3C, 0x01, 0x25, 0x04, 0x7E, 0x0D, 0xE0, 0x00, 0xBF, + 0x00, 0xEB, 0x05, 0x08, + 0x98, 0xF9, 0x12, 0x80, 0x88, 0x45, 0x05, 0xDB, 0x90, 0x45, 0x03, 0xDC, + 0x43, 0x19, 0x93, 0xF9, + 0x12, 0x30, 0x02, 0xE0, 0x6D, 0x1C, 0xAC, 0x42, 0xF0, 0xD2, 0x64, 0x1C, + 0x0A, 0xE0, 0x05, 0x19, + 0x95, 0xF9, 0x12, 0x50, 0x8D, 0x42, 0x05, 0xDB, 0x95, 0x42, 0x03, 0xDC, + 0x20, 0x44, 0x90, 0xF9, + 0x12, 0x70, 0x01, 0xE0, 0x64, 0x1E, 0xF2, 0xD1, 0xBB, 0x42, 0x09, 0xD1, + 0x0A, 0xE0, 0x00, 0xBF, + 0x39, 0xF9, 0x13, 0x00, 0xB0, 0x42, 0x02, 0xDA, 0x06, 0x46, 0x4F, 0xFA, + 0x83, 0xFC, 0x5B, 0x1C, + 0xBB, 0x42, 0xF5, 0xDD, 0x60, 0x46, 0xBD, 0xE8, 0xF0, 0x83, 0x2D, 0xE9, + 0xF0, 0x41, 0x17, 0x46, + 0x0E, 0x46, 0x04, 0x46, 0xC2, 0x78, 0x81, 0x78, 0x0E, 0x48, 0xFF, 0xF7, + 0xA4, 0xFF, 0x05, 0x00, + 0x06, 0xD1, 0xE2, 0x78, 0xA1, 0x78, 0x11, 0x4B, 0x0A, 0x48, 0xFF, 0xF7, + 0xB2, 0xFF, 0x30, 0x70, + 0x62, 0x78, 0x21, 0x78, 0x08, 0x48, 0xFF, 0xF7, 0x96, 0xFF, 0x06, 0x00, + 0x06, 0xD1, 0x62, 0x78, + 0x21, 0x78, 0x0B, 0x4B, 0x04, 0x48, 0xFF, 0xF7, 0xA4, 0xFF, 0x38, 0x70, + 0x05, 0xEA, 0x06, 0x00, + 0xBD, 0xE8, 0xF0, 0x81, 0x18, 0x2A, 0x10, 0x00, 0x58, 0x2A, 0x10, 0x00, + 0x04, 0x07, 0x10, 0x00, + 0x40, 0x2B, 0x10, 0x00, 0x0A, 0x0C, 0x01, 0x20, 0x21, 0x0C, 0x01, 0x20, + 0x94, 0x0B, 0x01, 0x20, + 0xBE, 0x0B, 0x01, 0x20, 0x24, 0x48, 0x00, 0x21, 0x01, 0x61, 0x41, 0x61, + 0x23, 0x48, 0x01, 0x70, + 0x01, 0x21, 0x41, 0x70, 0x70, 0x47, 0x2D, 0xE9, 0xF8, 0x4F, 0x20, 0x4D, + 0x82, 0x46, 0x0E, 0x46, + 0x1D, 0x48, 0x69, 0x78, 0x10, 0x30, 0x01, 0x29, 0x0F, 0xD1, 0x1D, 0x49, + 0x09, 0x68, 0x91, 0xF8, + 0x40, 0x2A, 0x02, 0xF0, 0x0F, 0x03, 0x03, 0x80, 0x12, 0x09, 0x42, 0x80, + 0x91, 0xF8, 0x41, 0x1A, + 0x01, 0xF0, 0x0F, 0x02, 0x82, 0x80, 0x09, 0x09, 0xC1, 0x80, 0x13, 0x49, + 0x00, 0x27, 0x3C, 0x46, + 0x8F, 0x60, 0xCF, 0x60, 0x80, 0x46, 0x89, 0x46, 0x0B, 0xE0, 0x68, 0x78, + 0x00, 0x90, 0x38, 0xF9, + 0x14, 0x30, 0x0A, 0xEB, 0x44, 0x01, 0x09, 0xEB, 0x44, 0x00, 0x01, 0x22, + 0x0D, 0xF0, 0xDE, 0xFF, + 0x64, 0x1C, 0xB4, 0x42, 0xF1, 0xDB, 0x6F, 0x70, 0x03, 0x20, 0xFA, 0xF7, + 0xAA, 0xFA, 0x06, 0x49, + 0x33, 0x46, 0x08, 0x4A, 0x01, 0xF1, 0x08, 0x00, 0x0D, 0xF0, 0xC3, 0xFF, + 0xBD, 0xE8, 0xF8, 0x4F, + 0x03, 0x20, 0xFA, 0xF7, 0xB9, 0xBA, 0x00, 0x00, 0x7A, 0x09, 0x01, 0x20, + 0x55, 0x05, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0xFC, 0x4A, 0x01, 0x20, 0x2D, 0xE9, 0xF0, 0x5F, + 0x82, 0x46, 0x5E, 0x48, + 0x99, 0x46, 0x3A, 0xF9, 0x12, 0x30, 0x00, 0x68, 0x01, 0x26, 0x0A, 0x9C, + 0xB0, 0xF9, 0x3E, 0xB2, + 0x03, 0xFB, 0x02, 0xF0, 0x35, 0x46, 0x29, 0xE0, 0x57, 0x1B, 0x7F, 0xB2, + 0x00, 0x2F, 0x0F, 0xDB, + 0x76, 0xB1, 0x3A, 0xF9, 0x17, 0xC0, 0xDC, 0x45, 0x09, 0xDD, 0x0A, 0xEB, + 0x47, 0x08, 0xB8, 0xF9, + 0x02, 0x80, 0xC4, 0x45, 0x03, 0xDC, 0x0C, 0xFB, 0x07, 0x00, 0x63, 0x44, + 0x00, 0xE0, 0x00, 0x26, + 0x57, 0x19, 0x7F, 0xB2, 0x8F, 0x42, 0x0F, 0xDA, 0x76, 0xB1, 0x3A, 0xF9, + 0x17, 0xC0, 0xDC, 0x45, + 0x09, 0xDD, 0x0A, 0xEB, 0x47, 0x08, 0x38, 0xF9, 0x02, 0x8C, 0xC4, 0x45, + 0x03, 0xDC, 0x0C, 0xFB, + 0x07, 0x00, 0x63, 0x44, 0x00, 0xE0, 0x00, 0x26, 0x6D, 0x1C, 0xED, 0xB2, + 0x4D, 0x45, 0xD3, 0xD9, + 0x49, 0x1E, 0x83, 0xFB, 0x01, 0x23, 0x80, 0xFB, 0x04, 0x01, 0x10, 0xF0, + 0x42, 0xFF, 0x00, 0x28, + 0x00, 0xDA, 0x00, 0x20, 0x61, 0x1E, 0x88, 0x42, 0x00, 0xDD, 0x08, 0x46, + 0xBD, 0xE8, 0xF0, 0x9F, + 0x70, 0xB5, 0x00, 0x20, 0x96, 0xB0, 0x04, 0x46, 0x38, 0x4D, 0x34, 0xE0, + 0x22, 0x46, 0x37, 0x49, + 0x01, 0xA8, 0x00, 0xF0, 0x35, 0xF8, 0x34, 0x4E, 0x30, 0x68, 0xB0, 0xF9, + 0x34, 0x10, 0x00, 0x91, + 0x90, 0xF8, 0x40, 0x32, 0x32, 0x48, 0x2A, 0x57, 0x01, 0x78, 0x32, 0x48, + 0xFF, 0xF7, 0x9C, 0xFF, + 0x13, 0x90, 0x30, 0x68, 0xB0, 0xF9, 0x32, 0x10, 0x00, 0x91, 0x90, 0xF8, + 0x40, 0x32, 0x28, 0x19, + 0x90, 0xF9, 0x02, 0x20, 0x2C, 0x48, 0x01, 0x78, 0x2C, 0x48, 0xFF, 0xF7, + 0x8D, 0xFF, 0x14, 0x90, + 0x13, 0xA8, 0x07, 0xF0, 0xB5, 0xF8, 0x14, 0x99, 0xAD, 0xF8, 0x12, 0x10, + 0x13, 0x98, 0xAD, 0xF8, + 0x16, 0x10, 0xAD, 0xF8, 0x10, 0x00, 0xAD, 0xF8, 0x14, 0x00, 0x01, 0xA8, + 0x05, 0xF0, 0xB5, 0xFE, + 0x01, 0x20, 0x64, 0x1C, 0xE4, 0xB2, 0x29, 0x7A, 0xA1, 0x42, 0xC7, 0xD8, + 0x16, 0xB0, 0x70, 0xBD, + 0x70, 0xB5, 0x0E, 0x46, 0x15, 0x46, 0x04, 0x46, 0x48, 0x21, 0x10, 0xF0, + 0xB7, 0xFF, 0x71, 0x19, + 0x08, 0x79, 0x8A, 0x79, 0x50, 0x43, 0x03, 0x22, 0x84, 0xF8, 0x40, 0x20, + 0x18, 0x4A, 0x12, 0x88, + 0x52, 0x1C, 0x62, 0x86, 0xA2, 0x8C, 0x42, 0xF0, 0x20, 0x02, 0xA2, 0x84, + 0xE0, 0x84, 0x60, 0x85, + 0x42, 0x1C, 0x22, 0x85, 0x41, 0xF2, 0x88, 0x32, 0xE2, 0x61, 0xA2, 0x61, + 0x0A, 0x79, 0x8B, 0x79, + 0xD1, 0x18, 0x00, 0xD1, 0x01, 0x21, 0x42, 0x43, 0x58, 0x43, 0x52, 0x00, + 0x40, 0x00, 0xB2, 0xFB, + 0xF1, 0xF2, 0xB0, 0xFB, 0xF1, 0xF0, 0x82, 0x42, 0x02, 0xD9, 0xE2, 0x85, + 0x20, 0x86, 0x70, 0xBD, + 0xE0, 0x85, 0x22, 0x86, 0x70, 0xBD, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x0C, 0x2A, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, 0x94, 0x0B, 0x01, 0x20, 0xEE, 0x06, 0x10, 0x00, + 0xBE, 0x0B, 0x01, 0x20, + 0x8C, 0x06, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x00, 0x25, 0x82, 0x46, + 0xA6, 0xB0, 0x50, 0x1E, + 0xC7, 0xB2, 0x2C, 0x46, 0x28, 0x46, 0x6B, 0x46, 0x0D, 0xF1, 0x4C, 0x09, + 0x12, 0xE0, 0x00, 0xBF, + 0x31, 0xF9, 0x10, 0x60, 0x35, 0x44, 0x46, 0x1C, 0xB4, 0x46, 0x95, 0xFB, + 0xF6, 0xF6, 0x23, 0xF8, + 0x10, 0x60, 0x3E, 0x1A, 0x40, 0x1C, 0x31, 0xF9, 0x16, 0x80, 0x44, 0x44, + 0x94, 0xFB, 0xFC, 0xFC, + 0x29, 0xF8, 0x16, 0xC0, 0x90, 0x42, 0xEB, 0xDB, 0x48, 0x46, 0x0C, 0xE0, + 0x33, 0xF9, 0x12, 0x40, + 0x30, 0xF9, 0x12, 0x50, 0x2C, 0x44, 0x31, 0xF8, 0x12, 0x50, 0x04, 0xEB, + 0xD4, 0x74, 0xA5, 0xEB, + 0x64, 0x04, 0x2A, 0xF8, 0x12, 0x40, 0x52, 0x1E, 0xF0, 0xD2, 0x26, 0xB0, + 0xBD, 0xE8, 0xF0, 0x87, + 0x2D, 0xE9, 0xFF, 0x4F, 0x4F, 0xF0, 0x00, 0x0B, 0xA7, 0xB0, 0xC0, 0xF8, + 0x00, 0xB0, 0x81, 0x46, + 0xC0, 0xF8, 0x04, 0xB0, 0x98, 0x46, 0x14, 0x46, 0x5D, 0x46, 0x5E, 0x46, + 0xDA, 0x46, 0x5F, 0x46, + 0x28, 0x21, 0x01, 0xA8, 0x10, 0xF0, 0x32, 0xFF, 0x4C, 0x21, 0x0B, 0xA8, + 0x10, 0xF0, 0x2E, 0xFF, + 0xCD, 0xF8, 0x00, 0x80, 0x02, 0x23, 0x22, 0x46, 0x0B, 0xA8, 0x28, 0x99, + 0x0D, 0xF0, 0x9E, 0xFE, + 0x8E, 0x49, 0x01, 0x20, 0x02, 0x46, 0x00, 0x23, 0x0D, 0xF1, 0x04, 0x0E, + 0xD1, 0xF8, 0x00, 0x80, + 0x17, 0xE0, 0x0B, 0xA9, 0x31, 0xF9, 0x10, 0xC0, 0xB8, 0xF9, 0x4C, 0x12, + 0x8C, 0x45, 0x04, 0xDD, + 0x4F, 0xF0, 0x01, 0x0B, 0x0E, 0xF8, 0x00, 0x20, 0x0A, 0xE0, 0x49, 0x42, + 0x8C, 0x45, 0x05, 0xDA, + 0xFF, 0x21, 0x4F, 0xF0, 0x01, 0x0B, 0x0E, 0xF8, 0x00, 0x10, 0x01, 0xE0, + 0x0E, 0xF8, 0x00, 0x30, + 0x40, 0x1C, 0xA0, 0x42, 0xE5, 0xDB, 0xBB, 0xF1, 0x01, 0x0F, 0x42, 0xD1, + 0x01, 0x20, 0x71, 0x46, + 0x09, 0xE0, 0x0A, 0x5C, 0x32, 0xB1, 0xC5, 0xB2, 0x08, 0x56, 0x00, 0x28, + 0x05, 0xDD, 0x4F, 0xF0, + 0x01, 0x0A, 0x02, 0xE0, 0x40, 0x1C, 0xA0, 0x42, 0xF3, 0xDB, 0x60, 0x1E, + 0x07, 0xE0, 0x0A, 0x5C, + 0x2A, 0xB1, 0xC6, 0xB2, 0x08, 0x56, 0x00, 0x28, 0x03, 0xDA, 0x01, 0x27, + 0x01, 0xE0, 0x40, 0x1E, + 0xF5, 0xD2, 0xA4, 0xF1, 0x01, 0x08, 0xBA, 0xF1, 0x00, 0x0F, 0x01, 0xD0, + 0x97, 0xB9, 0x02, 0xE0, + 0x4F, 0xF0, 0x01, 0x05, 0x77, 0xB9, 0x08, 0xF0, 0xFF, 0x06, 0x0B, 0xE0, + 0xD9, 0xE9, 0x00, 0x47, + 0x2A, 0x46, 0x01, 0x20, 0x00, 0x21, 0x10, 0xF0, 0xF9, 0xFD, 0x04, 0x43, + 0x0F, 0x43, 0xC9, 0xE9, + 0x00, 0x47, 0x6D, 0x1C, 0xB5, 0x42, 0xF1, 0xDD, 0xD9, 0xE9, 0x00, 0x04, + 0x40, 0xF0, 0x01, 0x05, + 0x42, 0x46, 0x01, 0x20, 0x00, 0x21, 0x10, 0xF0, 0xE9, 0xFD, 0x05, 0x43, + 0x0C, 0x43, 0xC9, 0xE9, + 0x00, 0x54, 0x2B, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xF8, 0x43, + 0x05, 0x46, 0x16, 0x46, + 0x0F, 0x46, 0x03, 0x20, 0xFA, 0xF7, 0xFD, 0xF8, 0x55, 0x4C, 0x56, 0x4A, + 0x29, 0x46, 0x23, 0x78, + 0x55, 0x48, 0x0D, 0xF0, 0x16, 0xFE, 0x55, 0x4D, 0x53, 0x48, 0x55, 0x4A, + 0x2B, 0x78, 0x39, 0x46, + 0x2A, 0x30, 0x0D, 0xF0, 0x0E, 0xFE, 0x03, 0x20, 0xFA, 0xF7, 0x06, 0xF9, + 0xDF, 0xF8, 0x2C, 0x81, + 0xD8, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0xE0, 0x13, 0x89, 0x07, 0x12, 0xD5, + 0x90, 0xF8, 0xF4, 0x03, + 0x00, 0x96, 0x00, 0xF0, 0x0F, 0x07, 0x3B, 0x46, 0x22, 0x78, 0x47, 0x49, + 0x49, 0x48, 0x0D, 0xF0, + 0x05, 0xFE, 0x45, 0x49, 0x00, 0x96, 0x3B, 0x46, 0x2A, 0x78, 0x2A, 0x31, + 0x46, 0x48, 0x0D, 0xF0, + 0xFD, 0xFD, 0x22, 0x78, 0x40, 0x49, 0x45, 0x48, 0x00, 0xF0, 0x5B, 0xF8, + 0x3E, 0x49, 0x2A, 0x78, + 0x2A, 0x31, 0x43, 0x48, 0x00, 0xF0, 0x55, 0xF8, 0x42, 0x4F, 0x00, 0x96, + 0x22, 0x78, 0x3F, 0x49, + 0x41, 0x48, 0x3B, 0x68, 0x0D, 0xF0, 0xEA, 0xFD, 0x00, 0x96, 0x2A, 0x78, + 0x3C, 0x49, 0x3F, 0x48, + 0x3B, 0x68, 0x0D, 0xF0, 0xE3, 0xFD, 0xD8, 0xF8, 0x00, 0x00, 0x47, 0x46, + 0x90, 0xF8, 0x30, 0x02, + 0xC0, 0x06, 0x0A, 0xD5, 0x22, 0x78, 0x38, 0x49, 0x39, 0x48, 0xFF, 0xF7, + 0xE3, 0xFE, 0x2A, 0x78, + 0x36, 0x49, 0x38, 0x48, 0xFF, 0xF7, 0xDE, 0xFE, 0x0B, 0xE0, 0x20, 0x78, + 0x32, 0x49, 0x42, 0x00, + 0x33, 0x48, 0x10, 0xF0, 0xB2, 0xFD, 0x28, 0x78, 0x30, 0x49, 0x42, 0x00, + 0x31, 0x48, 0x10, 0xF0, + 0xAC, 0xFD, 0x38, 0x68, 0x90, 0xF8, 0x30, 0x02, 0x80, 0x06, 0x04, 0xD5, + 0x2C, 0x49, 0x22, 0x78, + 0x08, 0x46, 0x00, 0xF0, 0x30, 0xF8, 0x38, 0x68, 0x90, 0xF8, 0x30, 0x02, + 0x40, 0x06, 0x04, 0xD5, + 0x28, 0x49, 0x2A, 0x78, 0x08, 0x46, 0x00, 0xF0, 0x26, 0xF8, 0x33, 0x46, + 0x22, 0x78, 0x1A, 0x49, + 0x25, 0x48, 0xFF, 0xF7, 0xED, 0xFE, 0x2A, 0x78, 0x01, 0xB0, 0x33, 0x46, + 0xBD, 0xE8, 0xF0, 0x43, + 0x15, 0x49, 0x21, 0x48, 0x2A, 0x31, 0x08, 0x30, 0xE2, 0xE6, 0x20, 0x49, + 0x00, 0x20, 0x08, 0x70, + 0x70, 0x47, 0x30, 0xB5, 0x00, 0x23, 0x03, 0x80, 0x01, 0x23, 0x09, 0xE0, + 0x00, 0xEB, 0x43, 0x04, + 0x31, 0xF8, 0x13, 0x50, 0x34, 0xF8, 0x02, 0x4C, 0x2C, 0x44, 0x20, 0xF8, + 0x13, 0x40, 0x5B, 0x1C, + 0x93, 0x42, 0xF3, 0xDB, 0x30, 0xBD, 0x08, 0xB5, 0x00, 0x92, 0x04, 0x4A, + 0x12, 0x68, 0xB2, 0xF9, + 0x4A, 0x32, 0xB2, 0xF9, 0x48, 0x22, 0x02, 0xF0, 0x78, 0xFA, 0x08, 0xBD, + 0x4C, 0x07, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, 0x7E, 0x4A, 0x01, 0x20, 0x92, 0x09, 0x01, 0x20, + 0xEE, 0x06, 0x10, 0x00, + 0xA8, 0x4A, 0x01, 0x20, 0xC8, 0x2A, 0x10, 0x00, 0xF2, 0x2A, 0x10, 0x00, + 0xA0, 0x0A, 0x01, 0x20, + 0xCE, 0x0A, 0x01, 0x20, 0x9C, 0x06, 0x10, 0x00, 0x1E, 0x0B, 0x01, 0x20, + 0x48, 0x0B, 0x01, 0x20, + 0x94, 0x0B, 0x01, 0x20, 0xBE, 0x0B, 0x01, 0x20, 0x50, 0x2B, 0x10, 0x00, + 0xF4, 0x06, 0x10, 0x00, + 0x10, 0xB5, 0x40, 0x21, 0xFE, 0x48, 0x10, 0xF0, 0xE1, 0xFD, 0xFD, 0x48, + 0x40, 0x21, 0x40, 0x30, + 0x10, 0xF0, 0xDC, 0xFD, 0xFA, 0x48, 0x00, 0x21, 0x80, 0x30, 0xC0, 0xE9, + 0x00, 0x11, 0xC0, 0xE9, + 0x02, 0x11, 0x10, 0x30, 0xC0, 0xE9, 0x00, 0x11, 0xC0, 0xE9, 0x02, 0x11, + 0x10, 0x30, 0xC0, 0xE9, + 0x00, 0x11, 0xC0, 0xE9, 0x02, 0x11, 0x08, 0x46, 0xF2, 0x49, 0x08, 0x60, + 0x10, 0xBD, 0x2D, 0xE9, + 0xFF, 0x5F, 0x06, 0x46, 0x89, 0x46, 0xF0, 0x48, 0xF0, 0x49, 0x98, 0x46, + 0x00, 0x78, 0x09, 0x68, + 0x14, 0x46, 0x01, 0x28, 0x50, 0xD0, 0xB1, 0xF9, 0x86, 0xA2, 0x91, 0xF8, + 0x88, 0x52, 0xB1, 0xF9, + 0x82, 0x72, 0x11, 0x46, 0x48, 0x46, 0x0D, 0xF0, 0xAE, 0xFD, 0x83, 0x46, + 0x21, 0x46, 0x48, 0x46, + 0x0D, 0xF0, 0xB4, 0xFD, 0x00, 0x90, 0x39, 0x46, 0x58, 0x46, 0x0C, 0xF0, + 0x91, 0xFD, 0x0F, 0xFA, + 0x80, 0xFB, 0x39, 0x46, 0x00, 0x98, 0x0C, 0xF0, 0x8B, 0xFD, 0x00, 0xB2, + 0xAB, 0xEB, 0x00, 0x00, + 0x68, 0x43, 0x64, 0x21, 0x90, 0xFB, 0xF1, 0xF0, 0x38, 0x44, 0x05, 0xB2, + 0xA8, 0xF8, 0x08, 0x50, + 0x70, 0x1C, 0x00, 0x21, 0x03, 0x90, 0xC8, 0xF8, 0x00, 0x10, 0xC8, 0xF8, + 0x04, 0x10, 0xB9, 0xF9, + 0x00, 0x00, 0xA8, 0x42, 0x02, 0xDD, 0x03, 0x99, 0x01, 0x20, 0x08, 0x70, + 0x09, 0xEB, 0x44, 0x00, + 0x76, 0x1C, 0x30, 0xF9, 0x02, 0x2C, 0x31, 0x19, 0xAA, 0x42, 0x02, 0xDD, + 0x01, 0x22, 0x01, 0xF8, + 0x01, 0x2C, 0xB9, 0xF9, 0x02, 0x30, 0x03, 0xEB, 0x0A, 0x02, 0x12, 0xB2, + 0xAB, 0x42, 0x18, 0xDD, + 0xB9, 0xF9, 0x00, 0x30, 0x93, 0x42, 0x03, 0xDD, 0xB9, 0xF9, 0x04, 0x30, + 0x93, 0x42, 0x0A, 0xDC, + 0x03, 0x9B, 0x01, 0x22, 0x5A, 0x70, 0x0C, 0xE0, 0xB1, 0xF9, 0x69, 0xA2, + 0x91, 0xF8, 0x64, 0x52, + 0xB1, 0xF9, 0x65, 0x72, 0xAD, 0xE7, 0xD8, 0xF8, 0x00, 0x60, 0x46, 0xF0, + 0x02, 0x06, 0xC8, 0xF8, + 0x00, 0x60, 0x30, 0xF9, 0x04, 0x3C, 0xA4, 0xF1, 0x02, 0x0B, 0x03, 0xEB, + 0x0A, 0x02, 0x12, 0xB2, + 0xAB, 0x42, 0x16, 0xDD, 0x30, 0xF9, 0x06, 0x3C, 0x93, 0x42, 0x03, 0xDD, + 0x30, 0xF9, 0x02, 0x0C, + 0x90, 0x42, 0x03, 0xDC, 0x01, 0x20, 0x01, 0xF8, 0x02, 0x0C, 0x0A, 0xE0, + 0xD8, 0xE9, 0x00, 0x64, + 0x5A, 0x46, 0x01, 0x20, 0x00, 0x21, 0x10, 0xF0, 0x69, 0xFC, 0x06, 0x43, + 0x0C, 0x43, 0xC8, 0xE9, + 0x00, 0x64, 0x02, 0x24, 0x58, 0xE0, 0x00, 0xBF, 0x39, 0xF9, 0x14, 0x00, + 0xA8, 0x42, 0x52, 0xDD, + 0x09, 0xEB, 0x44, 0x01, 0x02, 0x91, 0x50, 0x44, 0x31, 0xF9, 0x02, 0x1C, + 0x00, 0xB2, 0x81, 0x42, + 0x04, 0xDD, 0x02, 0x9A, 0xB2, 0xF9, 0x02, 0x20, 0x82, 0x42, 0x10, 0xDC, + 0x02, 0x9A, 0x32, 0xF9, + 0x04, 0x2C, 0x82, 0x42, 0x04, 0xDD, 0x02, 0x9A, 0xB2, 0xF9, 0x02, 0x20, + 0x82, 0x42, 0x06, 0xDC, + 0x81, 0x42, 0x35, 0xDD, 0x02, 0x99, 0xB1, 0xF9, 0x04, 0x10, 0x81, 0x42, + 0x30, 0xDD, 0xD8, 0xE9, + 0x00, 0x67, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x10, 0xF0, 0x38, 0xFC, + 0xCD, 0xE9, 0x00, 0x01, + 0x06, 0x43, 0x0F, 0x43, 0x62, 0x1E, 0x01, 0x20, 0x00, 0x21, 0xC8, 0xE9, + 0x00, 0x67, 0x10, 0xF0, + 0x2D, 0xFC, 0x02, 0x46, 0x0B, 0x46, 0x06, 0xEA, 0x02, 0x00, 0x07, 0xEA, + 0x03, 0x01, 0x08, 0x43, + 0x19, 0xD0, 0x02, 0x98, 0x39, 0xF9, 0x14, 0x10, 0x30, 0xF9, 0x02, 0x0C, + 0x81, 0x42, 0x09, 0xDA, + 0x96, 0x43, 0x9F, 0x43, 0xC8, 0xE9, 0x00, 0x67, 0x03, 0x99, 0x01, 0x20, + 0x21, 0x44, 0x01, 0xF8, + 0x01, 0x0C, 0x08, 0xE0, 0xDD, 0xE9, 0x00, 0x10, 0x8E, 0x43, 0x87, 0x43, + 0xC8, 0xE9, 0x00, 0x67, + 0x03, 0x99, 0x01, 0x20, 0x08, 0x55, 0x64, 0x1C, 0x5C, 0x45, 0xA5, 0xD3, + 0xBD, 0xE8, 0xFF, 0x9F, + 0x2D, 0xE9, 0xFF, 0x4F, 0x81, 0xB0, 0x82, 0x46, 0x00, 0x21, 0x1D, 0x46, + 0x19, 0x76, 0x06, 0x20, + 0x90, 0x46, 0xC3, 0x1F, 0x7A, 0x4C, 0x07, 0xE0, 0x00, 0x22, 0x29, 0x18, + 0x0A, 0x73, 0x8B, 0x74, + 0x05, 0xEB, 0x40, 0x01, 0x22, 0x88, 0x0A, 0x80, 0x40, 0x1E, 0xF5, 0xD2, + 0x72, 0x48, 0x01, 0x78, + 0x72, 0x48, 0x01, 0x29, 0x00, 0x68, 0x06, 0xD0, 0xB0, 0xF9, 0x84, 0x22, + 0x4F, 0xF0, 0x00, 0x0B, + 0x59, 0x46, 0x58, 0x46, 0x16, 0xE0, 0xB0, 0xF9, 0x67, 0x22, 0xF7, 0xE7, + 0x0A, 0xEB, 0x00, 0x03, + 0x5C, 0x78, 0x74, 0xB1, 0x1A, 0xF8, 0x00, 0x40, 0x0C, 0xB9, 0x49, 0x1C, + 0xC9, 0xB2, 0x59, 0x70, + 0x02, 0x9B, 0x33, 0xF9, 0x10, 0x30, 0x93, 0x42, 0x03, 0xDD, 0x01, 0x23, + 0x8B, 0x40, 0x43, 0xEA, + 0x0B, 0x0B, 0x40, 0x1C, 0x40, 0x45, 0xE9, 0xD3, 0x62, 0x48, 0x00, 0x90, + 0x0E, 0x98, 0x4F, 0xF0, + 0x00, 0x09, 0x4C, 0x46, 0xC0, 0xE9, 0x00, 0x99, 0x37, 0xE0, 0x00, 0xBF, + 0x0A, 0xEB, 0x04, 0x00, + 0x42, 0x78, 0x8A, 0xB3, 0x01, 0x21, 0x91, 0x40, 0x11, 0xEA, 0x0B, 0x0F, + 0x02, 0xD1, 0x00, 0x21, + 0x41, 0x70, 0x29, 0xE0, 0x1A, 0xF8, 0x04, 0x10, 0x39, 0xB9, 0x09, 0xF1, + 0x01, 0x01, 0x01, 0xF0, + 0xFF, 0x09, 0x54, 0x49, 0x00, 0x91, 0x05, 0xF8, 0x19, 0x40, 0x80, 0xF8, + 0x01, 0x90, 0x0E, 0x98, + 0x22, 0x46, 0x00, 0x21, 0xD0, 0xE9, 0x00, 0x67, 0x01, 0x20, 0x10, 0xF0, + 0x9F, 0xFB, 0x06, 0x43, + 0x0E, 0x98, 0x0F, 0x43, 0xC0, 0xE9, 0x00, 0x67, 0x05, 0xEB, 0x09, 0x00, + 0x01, 0x7B, 0x49, 0x1C, + 0x01, 0x73, 0x05, 0xEB, 0x49, 0x01, 0x4C, 0x70, 0x02, 0x99, 0x00, 0x9A, + 0x31, 0xF9, 0x14, 0x10, + 0x91, 0x42, 0x01, 0xDD, 0x00, 0x91, 0x84, 0x74, 0x64, 0x1C, 0x44, 0x45, + 0xC6, 0xD3, 0x85, 0xF8, + 0x18, 0x90, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xF8, 0x4F, + 0x0C, 0x46, 0x05, 0x46, + 0x1E, 0x46, 0x91, 0x46, 0x17, 0x21, 0x3C, 0x48, 0x10, 0xF0, 0x2E, 0xFC, + 0x28, 0x21, 0x3B, 0x48, + 0x10, 0xF0, 0x2A, 0xFC, 0xDF, 0xF8, 0xE8, 0xA0, 0x3A, 0x4F, 0x09, 0xF1, + 0x08, 0x08, 0x9A, 0xF8, + 0x00, 0x10, 0x76, 0xB1, 0x0A, 0x46, 0x05, 0xF1, 0x20, 0x03, 0x37, 0x49, + 0x32, 0x48, 0xFF, 0xF7, + 0x76, 0xFE, 0x04, 0xF1, 0x20, 0x03, 0x3A, 0x78, 0x34, 0x49, 0x30, 0x48, + 0xFF, 0xF7, 0x6F, 0xFE, + 0x11, 0xE0, 0x4A, 0x46, 0x2C, 0x48, 0x00, 0xF0, 0x3D, 0xFA, 0x42, 0x46, + 0x39, 0x78, 0x2B, 0x48, + 0x00, 0xF0, 0x38, 0xFA, 0x00, 0x20, 0xC5, 0xE9, 0x08, 0x00, 0xC4, 0xE9, + 0x08, 0x00, 0x2C, 0x48, + 0x00, 0x88, 0x28, 0x85, 0x20, 0x85, 0x2B, 0x4E, 0x28, 0x8D, 0x2B, 0x46, + 0x26, 0xF8, 0x11, 0x0F, + 0x20, 0x8D, 0x70, 0x80, 0xCD, 0xF8, 0x00, 0x90, 0x9A, 0xF8, 0x00, 0x20, + 0x22, 0x49, 0x1E, 0x48, + 0xFF, 0xF7, 0x36, 0xFF, 0xCD, 0xF8, 0x00, 0x80, 0x23, 0x46, 0x3A, 0x78, + 0x1F, 0x49, 0x1B, 0x48, + 0xFF, 0xF7, 0x2E, 0xFF, 0x29, 0x7E, 0x30, 0x79, 0x61, 0xF3, 0x03, 0x00, + 0x30, 0x71, 0x21, 0x7E, + 0x61, 0xF3, 0x07, 0x10, 0x30, 0x71, 0xBD, 0xE8, 0xF8, 0x8F, 0x2D, 0xE9, + 0xFF, 0x4F, 0x15, 0x46, + 0x04, 0x46, 0xD1, 0xE9, 0x02, 0x70, 0xD1, 0xE9, 0x00, 0x92, 0x80, 0x46, + 0x81, 0xB0, 0x92, 0x46, + 0x4F, 0xF4, 0x66, 0x71, 0x28, 0x46, 0x10, 0xF0, 0xCF, 0xFB, 0x00, 0x20, + 0x01, 0x46, 0x00, 0x90, + 0x0E, 0x98, 0x01, 0x60, 0x00, 0x21, 0x28, 0x46, 0x10, 0xF0, 0xD8, 0xFC, + 0x83, 0x46, 0x1B, 0xE0, + 0x18, 0x2A, 0x10, 0x00, 0x58, 0x05, 0x10, 0x00, 0x66, 0x05, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0xFC, 0x78, 0x01, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0x0A, 0x0C, 0x01, 0x20, + 0x21, 0x0C, 0x01, 0x20, + 0xED, 0x06, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, 0x94, 0x0B, 0x01, 0x20, + 0xBE, 0x0B, 0x01, 0x20, + 0x68, 0x05, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, 0x00, 0x21, 0x20, 0x46, + 0x10, 0xF0, 0xAE, 0xFC, + 0x06, 0x46, 0x00, 0x25, 0x34, 0xE0, 0x2A, 0x46, 0x01, 0x20, 0x00, 0x21, + 0x10, 0xF0, 0xE6, 0xFA, + 0x00, 0xEA, 0x09, 0x00, 0x01, 0xEA, 0x0A, 0x01, 0x08, 0x43, 0x22, 0xD0, + 0x00, 0x24, 0x1C, 0xE0, + 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x10, 0xF0, 0xD9, 0xFA, 0x38, 0x40, + 0x01, 0xEA, 0x08, 0x01, + 0x08, 0x43, 0x11, 0xD0, 0x36, 0xF9, 0x14, 0x10, 0x04, 0x98, 0x81, 0x42, + 0x0C, 0xDD, 0x01, 0x20, + 0x0B, 0xF8, 0x04, 0x00, 0x00, 0x98, 0x40, 0x1C, 0x00, 0x90, 0x0E, 0x98, + 0x36, 0xF9, 0x14, 0x10, + 0x00, 0x68, 0x01, 0x44, 0x0E, 0x98, 0x01, 0x60, 0x64, 0x1C, 0xFE, 0x48, + 0x00, 0x78, 0x84, 0x42, + 0xDE, 0xDB, 0xFC, 0x48, 0x0B, 0xF1, 0x28, 0x0B, 0x6D, 0x1C, 0x00, 0x78, + 0x06, 0xEB, 0x40, 0x06, + 0xF9, 0x48, 0x00, 0x78, 0x85, 0x42, 0xC6, 0xDB, 0x00, 0x98, 0x2A, 0xE7, + 0x2D, 0xE9, 0xF0, 0x47, + 0x0F, 0x46, 0x1C, 0x46, 0x16, 0x46, 0x99, 0x78, 0x10, 0xF0, 0x62, 0xFC, + 0x05, 0x46, 0xA1, 0x78, + 0x38, 0x46, 0x10, 0xF0, 0x63, 0xFC, 0x02, 0x46, 0xEE, 0x48, 0x00, 0x23, + 0xA1, 0x78, 0x90, 0xF8, + 0x00, 0x90, 0x94, 0xF8, 0x03, 0xC0, 0x13, 0xE0, 0x20, 0x78, 0x67, 0x78, + 0x09, 0xE0, 0x00, 0xBF, + 0x15, 0xF8, 0x00, 0x80, 0xB0, 0x45, 0x02, 0xD1, 0x32, 0xF9, 0x10, 0x80, + 0x43, 0x44, 0x40, 0x1C, + 0xC0, 0xB2, 0x87, 0x42, 0xF4, 0xD2, 0x49, 0x1C, 0x02, 0xEB, 0x49, 0x02, + 0xC9, 0xB2, 0x28, 0x35, + 0x8C, 0x45, 0xE9, 0xD2, 0x18, 0x46, 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, + 0xF0, 0x4F, 0xDF, 0x48, + 0x87, 0xB0, 0xDF, 0xF8, 0x80, 0x83, 0x06, 0x68, 0x00, 0x20, 0x06, 0xF5, + 0x88, 0x74, 0x86, 0xF8, + 0x0E, 0x01, 0xDB, 0x48, 0x01, 0x23, 0x00, 0x22, 0x00, 0x68, 0x30, 0x60, + 0x31, 0x46, 0xD8, 0xF8, + 0x00, 0x00, 0x08, 0xF0, 0x85, 0xF8, 0xDF, 0xF8, 0x60, 0xA3, 0xDF, 0xF8, + 0x60, 0x93, 0x4F, 0xF0, + 0xFF, 0x37, 0x9A, 0xF8, 0x00, 0x00, 0x01, 0x28, 0x10, 0xD1, 0xD5, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0x51, 0x02, 0xC0, 0x07, 0x01, 0xD0, 0x02, 0x23, 0x00, 0xE0, 0x01, 0x23, + 0x32, 0x46, 0xD9, 0xF8, + 0x00, 0x10, 0xD8, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x4D, 0xF9, 0x07, 0x46, + 0xCD, 0x49, 0x96, 0xF8, + 0x0E, 0x01, 0x48, 0x71, 0x00, 0x20, 0x01, 0x25, 0x05, 0x90, 0x51, 0xE0, + 0x01, 0x20, 0xA8, 0x40, + 0x38, 0x42, 0x4C, 0xD0, 0x06, 0xEB, 0x85, 0x00, 0x03, 0x90, 0x06, 0xEB, + 0x45, 0x00, 0x48, 0x21, + 0xB0, 0xF8, 0xB4, 0xB0, 0x20, 0x46, 0x10, 0xF0, 0x11, 0xFB, 0x03, 0x20, + 0x84, 0xF8, 0x40, 0x00, + 0xD9, 0xF8, 0x00, 0x00, 0x60, 0x60, 0xA0, 0x60, 0x84, 0xF8, 0x42, 0x50, + 0xA4, 0xF8, 0x2A, 0xB0, + 0xA4, 0xF8, 0x26, 0xB0, 0xE9, 0xB2, 0x23, 0x46, 0x03, 0x9A, 0xD8, 0xF8, + 0x00, 0x00, 0x07, 0xF0, + 0x40, 0xF8, 0x9A, 0xF8, 0x00, 0x00, 0x02, 0x28, 0x10, 0xD1, 0xB7, 0x48, + 0x04, 0xA9, 0xEA, 0xB2, + 0xB0, 0xF9, 0x00, 0x00, 0x02, 0x94, 0xCD, 0xE9, 0x00, 0x10, 0xD8, 0xF8, + 0x00, 0x10, 0x03, 0x9B, + 0x08, 0x46, 0x07, 0xF0, 0x68, 0xF8, 0xDD, 0xE9, 0x03, 0x01, 0x01, 0x60, + 0xE0, 0x8C, 0xB0, 0xB1, + 0xAD, 0x48, 0xB4, 0xF9, 0x32, 0x10, 0xB0, 0xF9, 0x00, 0x00, 0x81, 0x42, + 0x0F, 0xDD, 0x01, 0x20, + 0x05, 0x90, 0xE9, 0xB2, 0x23, 0x46, 0x03, 0x9A, 0xD8, 0xF8, 0x00, 0x00, + 0x08, 0xF0, 0x4A, 0xFA, + 0xE9, 0xB2, 0x23, 0x46, 0x03, 0x9A, 0xD8, 0xF8, 0x00, 0x00, 0x06, 0xF0, + 0x91, 0xFF, 0x6D, 0x1C, + 0x96, 0xF8, 0x0E, 0x01, 0xA8, 0x42, 0xA9, 0xD2, 0x05, 0x98, 0x07, 0xB0, + 0x6A, 0xE6, 0x9F, 0x49, + 0x10, 0xB5, 0x09, 0x78, 0x00, 0x20, 0x11, 0xB1, 0xFF, 0xF7, 0x67, 0xFF, + 0x04, 0xE0, 0x9C, 0x49, + 0x09, 0x7A, 0x09, 0xB1, 0xFF, 0xF7, 0xBC, 0xFA, 0x9A, 0x4A, 0x00, 0x21, + 0x11, 0x70, 0x9A, 0x4A, + 0x10, 0x70, 0x9A, 0x48, 0x01, 0x70, 0x10, 0xBD, 0x10, 0xB5, 0x91, 0x4C, + 0x20, 0x68, 0x90, 0xF8, + 0x30, 0x12, 0x09, 0x07, 0x1C, 0xD5, 0x96, 0x49, 0x09, 0x78, 0x11, 0xF0, + 0x30, 0x0F, 0x17, 0xD0, + 0xB0, 0xF9, 0x44, 0x12, 0x01, 0x22, 0x93, 0x48, 0x00, 0xF0, 0xEB, 0xFA, + 0x20, 0x68, 0x01, 0x22, + 0xB0, 0xF9, 0x46, 0x12, 0x8F, 0x48, 0x10, 0x30, 0x00, 0xF0, 0xE3, 0xFA, + 0x20, 0x68, 0x01, 0x22, + 0xB0, 0xF9, 0x42, 0x12, 0x8B, 0x48, 0xBD, 0xE8, 0x10, 0x40, 0x10, 0x38, + 0x00, 0xF0, 0xD9, 0xBA, + 0x88, 0x48, 0x4F, 0xF0, 0xFF, 0x31, 0xC0, 0xE9, 0x00, 0x11, 0xC0, 0xE9, + 0x02, 0x11, 0x10, 0x38, + 0xC0, 0xE9, 0x00, 0x11, 0xC0, 0xE9, 0x02, 0x11, 0x20, 0x30, 0xC0, 0xE9, + 0x00, 0x11, 0xC0, 0xE9, + 0x02, 0x11, 0x10, 0xBD, 0x2D, 0xE9, 0xFF, 0x5F, 0x15, 0x46, 0x03, 0x99, + 0x91, 0xF8, 0x40, 0x10, + 0x02, 0x29, 0x0C, 0xD0, 0x01, 0x29, 0x0C, 0xD0, 0x7A, 0x49, 0x10, 0x39, + 0x8A, 0x46, 0x4F, 0xF0, + 0x00, 0x0B, 0xA9, 0x78, 0x10, 0xF0, 0x5A, 0xFB, 0x81, 0x46, 0xA8, 0x78, + 0x2A, 0xE0, 0x75, 0x49, + 0xF4, 0xE7, 0x74, 0x49, 0x10, 0x31, 0xF1, 0xE7, 0x2C, 0x78, 0x1C, 0xE0, + 0x19, 0xF8, 0x04, 0x10, + 0x01, 0x98, 0x81, 0x42, 0x16, 0xD1, 0x01, 0x22, 0xDA, 0xF8, 0x00, 0x00, + 0x02, 0xFA, 0x08, 0xF2, + 0x10, 0x40, 0x00, 0x00, 0x24, 0xD0, 0xDA, 0xE9, 0x02, 0x76, 0x22, 0x46, + 0x01, 0x20, 0x00, 0x21, + 0x10, 0xF0, 0x74, 0xF9, 0x07, 0x40, 0x0E, 0x40, 0x37, 0x43, 0x19, 0xD0, + 0x0B, 0xF1, 0x01, 0x00, + 0x1F, 0xFA, 0x80, 0xFB, 0x64, 0x1C, 0x68, 0x78, 0xA0, 0x42, 0xDF, 0xDA, + 0x09, 0xF1, 0x28, 0x09, + 0x08, 0xF1, 0x01, 0x00, 0xE9, 0x78, 0x80, 0x46, 0x41, 0x45, 0xD5, 0xDA, + 0x03, 0x99, 0x5F, 0xEA, + 0x0B, 0x00, 0xA1, 0xF8, 0x26, 0xB0, 0x00, 0xD0, 0x01, 0x20, 0x04, 0xB0, + 0xBD, 0xE8, 0xF0, 0x9F, + 0x00, 0x21, 0x09, 0xF8, 0x04, 0x10, 0xE5, 0xE7, 0x2D, 0xE9, 0xF8, 0x4F, + 0x80, 0x46, 0x4F, 0xF0, + 0x00, 0x0B, 0x87, 0x78, 0x90, 0xF8, 0x03, 0xA0, 0x23, 0xE0, 0x00, 0xBF, + 0x52, 0x49, 0x01, 0x22, + 0xBA, 0x40, 0x08, 0x68, 0x98, 0xF8, 0x00, 0x40, 0x10, 0x40, 0x00, 0x90, + 0xD1, 0xE9, 0x02, 0x56, + 0x98, 0xF8, 0x01, 0x90, 0x12, 0xE0, 0x00, 0x99, 0x09, 0x00, 0x0E, 0xD0, + 0x22, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x10, 0xF0, 0x33, 0xF9, 0x05, 0xEA, 0x00, 0x02, 0x06, 0xEA, + 0x01, 0x00, 0x02, 0x43, + 0x03, 0xD0, 0x0B, 0xF1, 0x01, 0x00, 0x1F, 0xFA, 0x80, 0xFB, 0x64, 0x1C, + 0xA1, 0x45, 0xEA, 0xDA, + 0x7F, 0x1C, 0xBA, 0x45, 0xDA, 0xDA, 0xBB, 0xF1, 0x00, 0x0F, 0x01, 0xD0, + 0x01, 0x20, 0xF2, 0xE5, + 0x00, 0x20, 0xF0, 0xE5, 0x2D, 0xE9, 0xF0, 0x47, 0x91, 0x46, 0x45, 0x1C, + 0x0C, 0x46, 0x4F, 0xF0, + 0x01, 0x08, 0x0C, 0xE0, 0xD9, 0xE9, 0x00, 0x67, 0x22, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x10, 0xF0, + 0x0D, 0xF9, 0x06, 0x40, 0x0F, 0x40, 0x3E, 0x43, 0x01, 0xD0, 0x05, 0xF8, + 0x04, 0x80, 0x64, 0x1E, + 0xF0, 0xD2, 0x80, 0xE6, 0x2D, 0xE9, 0xF0, 0x47, 0x92, 0xF8, 0x0E, 0x41, + 0x86, 0xB0, 0x1D, 0x46, + 0x17, 0x46, 0x89, 0x46, 0x82, 0x46, 0xE8, 0x46, 0x05, 0x2C, 0x02, 0xD9, + 0x05, 0x24, 0x01, 0x26, + 0x01, 0xE0, 0x01, 0x26, 0x0C, 0xE0, 0x07, 0xEB, 0x86, 0x03, 0x32, 0x46, + 0x49, 0x46, 0x50, 0x46, + 0xFF, 0xF7, 0x3C, 0xFE, 0x08, 0xEB, 0x86, 0x01, 0x76, 0x1C, 0x41, 0xF8, + 0x04, 0x0C, 0xF6, 0xB2, + 0xA6, 0x42, 0xF0, 0xD9, 0x00, 0x20, 0x03, 0x46, 0x01, 0x22, 0x40, 0xE0, + 0x00, 0x27, 0x4F, 0xF0, + 0x00, 0x46, 0x01, 0x21, 0x0F, 0xE0, 0x00, 0xBF, 0x02, 0xFA, 0x01, 0xFC, + 0x1C, 0xEA, 0x00, 0x0F, + 0x07, 0xD1, 0x08, 0xEB, 0x81, 0x0C, 0x5C, 0xF8, 0x04, 0xCC, 0xB4, 0x45, + 0x01, 0xDD, 0x66, 0x46, + 0x0F, 0x46, 0x49, 0x1C, 0xC9, 0xB2, 0xA1, 0x42, 0xEE, 0xD9, 0x02, 0xFA, + 0x07, 0xF1, 0x08, 0x43, + 0x5B, 0x1C, 0x23, 0xE0, 0xEE, 0x06, 0x10, 0x00, 0xED, 0x06, 0x10, 0x00, + 0x58, 0x05, 0x10, 0x00, + 0x88, 0x06, 0x10, 0x00, 0x50, 0x06, 0x10, 0x00, 0x66, 0x05, 0x10, 0x00, + 0x14, 0x07, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, 0x92, 0x06, 0x10, 0x00, + 0x57, 0x05, 0x10, 0x00, + 0x0C, 0x2A, 0x10, 0x00, 0xF6, 0x06, 0x10, 0x00, 0xF7, 0x06, 0x10, 0x00, + 0xF8, 0x06, 0x10, 0x00, + 0x04, 0x07, 0x10, 0x00, 0xA8, 0x2A, 0x10, 0x00, 0x50, 0x2B, 0x10, 0x00, + 0xDB, 0xB2, 0xAB, 0x42, + 0xBC, 0xD3, 0x06, 0xB0, 0x17, 0xE6, 0x00, 0x00, 0xA1, 0x4A, 0x10, 0xB5, + 0x13, 0x68, 0x00, 0x21, + 0xB3, 0xF8, 0x14, 0x22, 0x82, 0x42, 0x05, 0xDA, 0x93, 0xF8, 0x10, 0x22, + 0x52, 0x07, 0x01, 0xD5, + 0x02, 0x21, 0x08, 0xE0, 0xB3, 0xF8, 0x12, 0x22, 0x82, 0x42, 0x04, 0xDA, + 0x93, 0xF8, 0x10, 0x02, + 0x80, 0x07, 0x00, 0xD5, 0x01, 0x21, 0x97, 0x48, 0x97, 0x4C, 0x42, 0x78, + 0x91, 0x42, 0x14, 0xD1, + 0xA1, 0x78, 0x91, 0x42, 0x0D, 0xD0, 0x95, 0x4B, 0x1B, 0x78, 0x1A, 0x43, + 0x94, 0x4B, 0x1B, 0x78, + 0x1A, 0x43, 0x07, 0xD0, 0x41, 0x68, 0x49, 0x1E, 0x41, 0x60, 0x00, 0x29, + 0x01, 0xDC, 0x40, 0x78, + 0xA0, 0x70, 0x10, 0xBD, 0x41, 0x70, 0x41, 0x68, 0xF7, 0xE7, 0x59, 0xB1, + 0x02, 0x29, 0x01, 0xD1, + 0x01, 0x2A, 0x07, 0xD0, 0x93, 0xF8, 0x18, 0x22, 0x42, 0x60, 0x41, 0x70, + 0x00, 0x2A, 0xF0, 0xDC, + 0xA1, 0x70, 0x10, 0xBD, 0x93, 0xF8, 0x19, 0x22, 0xF6, 0xE7, 0x70, 0xB5, + 0x85, 0x4A, 0x86, 0x4B, + 0x81, 0x4D, 0x16, 0x78, 0x7E, 0x4A, 0x1C, 0x78, 0x00, 0x21, 0x12, 0x68, + 0xAB, 0x78, 0x01, 0x2E, + 0x02, 0xD1, 0x82, 0x4E, 0x36, 0x78, 0x4E, 0xB1, 0xB2, 0xF8, 0x14, 0x62, + 0x86, 0x42, 0x17, 0xDA, + 0x92, 0xF8, 0x10, 0x62, 0x76, 0x07, 0x13, 0xD5, 0x02, 0x21, 0x25, 0xE0, + 0xB2, 0xF8, 0x1C, 0x62, + 0x86, 0x42, 0x03, 0xDA, 0x92, 0xF8, 0x10, 0x62, 0x76, 0x07, 0xF5, 0xD4, + 0xB2, 0xF8, 0x1A, 0x62, + 0x08, 0xE0, 0x00, 0xBF, 0x92, 0xF8, 0x10, 0x02, 0x80, 0x07, 0x05, 0xD5, + 0x01, 0x21, 0x13, 0xE0, + 0xB2, 0xF8, 0x12, 0x62, 0x86, 0x42, 0xF5, 0xDB, 0x73, 0xB1, 0x6C, 0x48, + 0x00, 0x78, 0x01, 0x28, + 0x03, 0xD0, 0x6B, 0x48, 0x00, 0x78, 0x01, 0x28, 0x03, 0xD1, 0x92, 0xF8, + 0x10, 0x02, 0x00, 0x07, + 0x01, 0xD5, 0x01, 0x2C, 0x00, 0xD1, 0x19, 0x46, 0x62, 0x48, 0x34, 0xB1, + 0x19, 0xB1, 0x00, 0xBF, + 0x92, 0xF8, 0x19, 0x22, 0x42, 0x60, 0xA9, 0x70, 0x70, 0xBD, 0x00, 0x29, + 0xF8, 0xD1, 0x00, 0x2B, + 0xF6, 0xD0, 0x44, 0x68, 0x00, 0x2C, 0xF6, 0xDD, 0x92, 0xF8, 0x10, 0x12, + 0x0A, 0x07, 0x59, 0x49, + 0x49, 0x68, 0xA1, 0xF1, 0x01, 0x01, 0x02, 0xD5, 0x5D, 0x4A, 0x12, 0x78, + 0x02, 0xB1, 0x41, 0x60, + 0x19, 0x46, 0xE8, 0xE7, 0x52, 0x48, 0x53, 0x49, 0x00, 0x68, 0x90, 0xF8, + 0x10, 0x02, 0xC2, 0x06, + 0x4F, 0xF0, 0x00, 0x00, 0x03, 0xD4, 0x50, 0x4A, 0x90, 0x70, 0x48, 0x70, + 0x48, 0x60, 0x08, 0x70, + 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, 0x4A, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0x10, 0x02, 0xC0, 0x06, + 0x20, 0x46, 0x02, 0xD5, 0xFF, 0xF7, 0x89, 0xFF, 0x01, 0xE0, 0xFF, 0xF7, + 0x45, 0xFF, 0x46, 0x48, + 0x82, 0x78, 0x4C, 0x48, 0x41, 0x7B, 0x62, 0xF3, 0x07, 0x11, 0x41, 0x73, + 0xA0, 0xF8, 0x2F, 0x40, + 0x10, 0xBD, 0x2D, 0xE9, 0xFC, 0x5F, 0x83, 0x46, 0x47, 0x48, 0x00, 0x25, + 0x0A, 0x46, 0x00, 0x78, + 0x2F, 0x46, 0x2C, 0x46, 0x01, 0x28, 0x00, 0xD1, 0x01, 0x24, 0x44, 0x48, + 0x06, 0x78, 0x00, 0x78, + 0x41, 0x00, 0x01, 0x2A, 0x1B, 0xD0, 0xDF, 0xF8, 0xD8, 0x80, 0xDF, 0xF8, + 0x04, 0xA1, 0xDF, 0xF8, + 0x04, 0x91, 0xD8, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x10, 0x22, 0x92, 0x06, + 0x14, 0xD5, 0x32, 0x1B, + 0xB0, 0xF9, 0x20, 0x12, 0xCD, 0xE9, 0x00, 0x12, 0xB0, 0xF9, 0x1E, 0x32, + 0x0A, 0xEB, 0x44, 0x02, + 0x0B, 0xEB, 0x44, 0x01, 0x09, 0xEB, 0x44, 0x00, 0x0C, 0xF0, 0x72, 0xFF, + 0x09, 0xE0, 0x34, 0x48, + 0x4C, 0x38, 0x10, 0xF0, 0x59, 0xF8, 0x41, 0xE0, 0x0A, 0x46, 0x59, 0x46, + 0x31, 0x48, 0x0F, 0xF0, + 0xD4, 0xFF, 0x2F, 0x48, 0x4C, 0x38, 0x34, 0xE0, 0x3A, 0xF9, 0x14, 0x20, + 0x39, 0xF9, 0x14, 0x10, + 0x51, 0x1A, 0x00, 0xD5, 0x49, 0x42, 0xD8, 0xF8, 0x00, 0x30, 0x09, 0xB2, + 0x93, 0xF8, 0x10, 0x22, + 0x52, 0x06, 0x0B, 0xD5, 0x20, 0x4A, 0x12, 0x78, 0x01, 0x2A, 0x07, 0xD1, + 0x26, 0x4A, 0x12, 0x78, + 0x22, 0xB9, 0xB3, 0xF8, 0x22, 0x22, 0x8A, 0x42, 0x00, 0xDA, 0x01, 0x27, + 0x30, 0xF9, 0x14, 0x20, + 0x8A, 0x42, 0x02, 0xDA, 0x93, 0xF8, 0x16, 0x32, 0x01, 0xE0, 0x93, 0xF8, + 0x17, 0x32, 0x5A, 0x43, + 0xC3, 0xF5, 0x80, 0x73, 0x01, 0xFB, 0x03, 0x21, 0xCA, 0x17, 0x01, 0xEB, + 0x12, 0x61, 0x09, 0x12, + 0x20, 0xF8, 0x14, 0x10, 0x30, 0xF9, 0x14, 0x10, 0xA9, 0x42, 0x00, 0xDD, + 0x0D, 0x46, 0x64, 0x1C, + 0x24, 0xB2, 0xB4, 0x42, 0xC8, 0xDB, 0x28, 0x46, 0xFF, 0xF7, 0x73, 0xFF, + 0x72, 0x00, 0x59, 0x46, + 0x0F, 0x48, 0x0F, 0xF0, 0x92, 0xFF, 0x03, 0x48, 0x07, 0x70, 0xBD, 0xE8, + 0xFC, 0x9F, 0x00, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x5C, 0x05, 0x10, 0x00, 0x74, 0x07, 0x10, 0x00, + 0xF5, 0x06, 0x10, 0x00, + 0x64, 0x05, 0x10, 0x00, 0xF6, 0x06, 0x10, 0x00, 0xFD, 0x06, 0x10, 0x00, + 0xF7, 0x06, 0x10, 0x00, + 0xFA, 0x06, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, 0xF4, 0x06, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, + 0x54, 0x0A, 0x01, 0x20, 0xA0, 0x0A, 0x01, 0x20, 0x74, 0x05, 0x10, 0x00, + 0x2D, 0xE9, 0xF0, 0x4F, + 0x81, 0x46, 0xDD, 0xE9, 0x09, 0xB5, 0x01, 0x20, 0x47, 0xF6, 0xFF, 0x77, + 0x9A, 0x46, 0x84, 0x46, + 0xFE, 0x43, 0x2C, 0x46, 0x15, 0xE0, 0x00, 0xBF, 0x32, 0xF8, 0x14, 0x30, + 0x31, 0xF8, 0x14, 0x80, + 0xA3, 0xEB, 0x08, 0x03, 0x1B, 0xB2, 0xBB, 0x42, 0x00, 0xDA, 0x1F, 0x46, + 0xB3, 0x42, 0x00, 0xDD, + 0x1E, 0x46, 0x00, 0x2B, 0x02, 0xDD, 0x4F, 0xF0, 0x00, 0x0C, 0x02, 0xE0, + 0x01, 0xDA, 0x4F, 0xF0, + 0x00, 0x00, 0x64, 0x1E, 0xE8, 0xD2, 0x20, 0xB1, 0xBC, 0xF1, 0x00, 0x0F, + 0x01, 0xD0, 0x00, 0x23, + 0x09, 0xE0, 0x50, 0xEA, 0x0C, 0x03, 0x06, 0xD0, 0x20, 0xB9, 0xBC, 0xF1, + 0x00, 0x0F, 0x01, 0xD0, + 0x33, 0x46, 0x00, 0xE0, 0x3B, 0x46, 0x00, 0x27, 0x3C, 0x46, 0x28, 0x46, + 0xCB, 0xF1, 0x00, 0x0C, + 0x0E, 0xE0, 0x00, 0xBF, 0x32, 0xF8, 0x10, 0x60, 0x31, 0xF8, 0x10, 0x80, + 0xA6, 0xEB, 0x08, 0x06, + 0xF6, 0x1A, 0x36, 0xB2, 0x56, 0x45, 0x03, 0xDA, 0x66, 0x45, 0x01, 0xDD, + 0x37, 0x44, 0x64, 0x1C, + 0x40, 0x1E, 0xEF, 0xD2, 0x04, 0xB9, 0x01, 0x24, 0x97, 0xFB, 0xF4, 0xF0, + 0x18, 0x44, 0x04, 0xE0, + 0x31, 0xF8, 0x15, 0x20, 0x02, 0x44, 0x29, 0xF8, 0x15, 0x20, 0x6D, 0x1E, + 0xF8, 0xD2, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, 0xF0, 0x41, 0x04, 0x46, 0x03, 0x46, 0xFC, 0x48, + 0x15, 0x46, 0x0E, 0x46, + 0x0A, 0x46, 0x01, 0x78, 0xFA, 0x48, 0x00, 0xF0, 0x51, 0xFA, 0xFA, 0x48, + 0x04, 0xF1, 0x08, 0x03, + 0x1F, 0x46, 0x01, 0x78, 0xF6, 0x48, 0x32, 0x46, 0x2A, 0x30, 0x00, 0xF0, + 0x47, 0xFA, 0x00, 0x2D, + 0x07, 0xD0, 0x20, 0x46, 0x10, 0xF0, 0x6C, 0xF8, 0x38, 0x46, 0xBD, 0xE8, + 0xF0, 0x41, 0x10, 0xF0, + 0x67, 0xB8, 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xFC, 0x41, 0x07, 0x46, + 0x14, 0x46, 0x88, 0x46, + 0x03, 0x20, 0xF9, 0xF7, 0xD6, 0xF9, 0xEC, 0x4D, 0xE8, 0x4E, 0x00, 0x94, + 0xE8, 0x48, 0x32, 0x78, + 0x39, 0x46, 0x76, 0x38, 0x2B, 0x68, 0x0C, 0xF0, 0xF9, 0xFE, 0x00, 0x94, + 0xE5, 0x4C, 0xE4, 0x48, + 0x41, 0x46, 0x22, 0x78, 0x4C, 0x38, 0x2B, 0x68, 0x0C, 0xF0, 0xF0, 0xFE, + 0xE3, 0x4D, 0x28, 0x68, + 0x90, 0xF8, 0x30, 0x12, 0xC9, 0x07, 0x1A, 0xD0, 0x32, 0x78, 0xB0, 0xF9, + 0x34, 0x12, 0xCD, 0xE9, + 0x00, 0x12, 0xDB, 0x49, 0xB0, 0xF9, 0x32, 0x32, 0x76, 0x39, 0xDD, 0x4A, + 0x08, 0x46, 0xFF, 0xF7, + 0x55, 0xFF, 0x28, 0x68, 0x22, 0x78, 0xB0, 0xF9, 0x38, 0x12, 0xCD, 0xE9, + 0x00, 0x12, 0xD4, 0x49, + 0xB0, 0xF9, 0x36, 0x32, 0x4C, 0x39, 0xD7, 0x4A, 0x08, 0x46, 0xFF, 0xF7, + 0x47, 0xFF, 0xD0, 0x49, + 0x33, 0x78, 0xD3, 0x4A, 0x76, 0x39, 0xCE, 0x48, 0x0C, 0xF0, 0xBB, 0xFE, + 0xCC, 0x49, 0x23, 0x78, + 0x4C, 0x39, 0xD0, 0x4A, 0x01, 0xF1, 0x76, 0x00, 0x0C, 0xF0, 0xB3, 0xFE, + 0x28, 0x68, 0x90, 0xF8, + 0x30, 0x12, 0x8A, 0x07, 0x04, 0xD4, 0xCC, 0x4A, 0x12, 0x78, 0x8A, 0xB1, + 0x49, 0x07, 0x0F, 0xD5, + 0xC3, 0x49, 0x90, 0xF8, 0x41, 0x32, 0x32, 0x78, 0x08, 0x46, 0x0C, 0xF0, + 0xE2, 0xFE, 0x28, 0x68, + 0xBF, 0x49, 0x22, 0x78, 0x90, 0xF8, 0x41, 0x32, 0x2A, 0x31, 0x08, 0x46, + 0x0C, 0xF0, 0xD9, 0xFE, + 0xBD, 0xE8, 0xFC, 0x41, 0x03, 0x20, 0xF9, 0xF7, 0x8F, 0xB9, 0x70, 0xB5, + 0xBF, 0x4C, 0xC0, 0x49, + 0x00, 0x25, 0xA5, 0x70, 0x01, 0x20, 0x08, 0x70, 0xB8, 0x48, 0x25, 0x70, + 0x65, 0x70, 0x00, 0x68, + 0xB0, 0xF8, 0x3A, 0x02, 0xA0, 0x80, 0x00, 0xF0, 0xE3, 0xF9, 0xFF, 0xF7, + 0xEE, 0xF8, 0xA5, 0x60, + 0xE5, 0x60, 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x0E, 0x46, 0xB5, 0x49, + 0x07, 0x46, 0xB3, 0x4C, + 0x0D, 0x78, 0x00, 0x20, 0x08, 0x70, 0x60, 0x70, 0x00, 0xF0, 0xD2, 0xF9, + 0xB1, 0x48, 0x2A, 0x46, + 0x31, 0x46, 0x00, 0x78, 0x00, 0x28, 0x38, 0x46, 0x02, 0xD0, 0xFF, 0xF7, + 0x45, 0xF8, 0x01, 0xE0, + 0xFF, 0xF7, 0x69, 0xFF, 0xAC, 0x48, 0x41, 0x78, 0xA4, 0x48, 0xA9, 0xB1, + 0xA1, 0x78, 0x01, 0x29, + 0x12, 0xD0, 0x00, 0x68, 0xB0, 0xF9, 0x3C, 0x12, 0xA8, 0x4D, 0xA1, 0x80, + 0x01, 0x22, 0x28, 0x46, + 0xFF, 0xF7, 0x37, 0xFF, 0xD5, 0xE9, 0x00, 0x01, 0x08, 0x43, 0x09, 0xD0, + 0xD5, 0xE9, 0x02, 0x01, + 0x08, 0x43, 0x05, 0xD0, 0x01, 0x20, 0x04, 0xE0, 0x00, 0x68, 0xB0, 0xF9, + 0x3A, 0x12, 0xEB, 0xE7, + 0x00, 0x20, 0x20, 0x70, 0x45, 0xE7, 0x2D, 0xE9, 0xF0, 0x4F, 0x04, 0x46, + 0x9C, 0x48, 0xA7, 0xB0, + 0x4F, 0xF0, 0x01, 0x09, 0x01, 0x78, 0x91, 0x48, 0x01, 0x29, 0x00, 0x68, + 0x15, 0xD0, 0x92, 0x49, + 0x09, 0x78, 0xA9, 0xB1, 0xB0, 0xF9, 0x54, 0x62, 0x88, 0x48, 0x00, 0x21, + 0x4F, 0xF0, 0x01, 0x0A, + 0x00, 0x78, 0x94, 0x4D, 0x40, 0x1E, 0x00, 0xF0, 0xFF, 0x08, 0x86, 0x48, + 0x83, 0x46, 0x03, 0x78, + 0x9A, 0x1E, 0x02, 0xF0, 0xFF, 0x0C, 0x22, 0x46, 0x13, 0xE0, 0xB0, 0xF9, + 0x59, 0x62, 0xEB, 0xE7, + 0xB0, 0xF9, 0x52, 0x62, 0xE8, 0xE7, 0x50, 0x46, 0x06, 0xE0, 0x00, 0xBF, + 0x32, 0xF9, 0x10, 0x70, + 0xAF, 0x42, 0x00, 0xDD, 0x3D, 0x46, 0x40, 0x1C, 0x60, 0x45, 0xF7, 0xDD, + 0x02, 0xEB, 0x43, 0x02, + 0x49, 0x1C, 0x41, 0x45, 0xEF, 0xDD, 0x5F, 0x46, 0x5A, 0x00, 0x04, 0xEB, + 0x43, 0x01, 0x68, 0x46, + 0x0F, 0xF0, 0xFB, 0xFD, 0x80, 0x4A, 0x38, 0x78, 0x6B, 0x46, 0x12, 0x88, + 0x41, 0x42, 0x02, 0xEB, + 0x41, 0x01, 0x09, 0xB2, 0x42, 0x00, 0x04, 0xEB, 0x41, 0x01, 0x03, 0xEB, + 0x40, 0x00, 0x0F, 0xF0, + 0xEC, 0xFD, 0x38, 0x78, 0x69, 0x46, 0x42, 0x00, 0x08, 0x46, 0x0C, 0xF0, + 0x50, 0xFE, 0x28, 0x1A, + 0x00, 0xB2, 0xB0, 0x42, 0x01, 0xDD, 0x4F, 0xF0, 0x00, 0x09, 0x48, 0x46, + 0x27, 0xB0, 0xC6, 0xE6, + 0x2D, 0xE9, 0xF0, 0x4F, 0x71, 0x49, 0x70, 0x4A, 0x00, 0x27, 0x0C, 0x68, + 0xB2, 0xF9, 0x00, 0x20, + 0x4F, 0xF0, 0x01, 0x0A, 0x21, 0x8E, 0x3B, 0x46, 0x91, 0x42, 0x49, 0xD1, + 0x62, 0x49, 0x0A, 0x78, + 0x5E, 0x49, 0x0E, 0x68, 0x8A, 0xB1, 0xB6, 0xF9, 0x54, 0x12, 0x00, 0x25, + 0x89, 0x46, 0x57, 0x49, + 0x4F, 0xF0, 0x02, 0x0E, 0x09, 0x78, 0x49, 0x1E, 0x01, 0xF0, 0xFF, 0x0B, + 0x55, 0x49, 0x09, 0x78, + 0xC9, 0x1E, 0x01, 0xF0, 0xFF, 0x0C, 0x32, 0x34, 0x2A, 0xE0, 0xB6, 0xF9, + 0x52, 0x12, 0xEC, 0xE7, + 0x72, 0x46, 0x1C, 0xE0, 0x34, 0xF8, 0x12, 0x10, 0x30, 0xF8, 0x12, 0x80, + 0xA1, 0xEB, 0x08, 0x01, + 0x09, 0xB2, 0x00, 0x29, 0x01, 0xDB, 0x88, 0x46, 0x01, 0xE0, 0xC1, 0xF1, + 0x00, 0x08, 0xB8, 0x45, + 0x05, 0xDD, 0x00, 0x29, 0x01, 0xDB, 0x0F, 0x46, 0x00, 0xE0, 0x4F, 0x42, + 0x3F, 0xB2, 0x00, 0x29, + 0x00, 0xDA, 0x49, 0x42, 0x49, 0x45, 0x01, 0xDD, 0x5B, 0x1C, 0x9B, 0xB2, + 0x52, 0x1C, 0x62, 0x45, + 0xE0, 0xDD, 0x96, 0xF8, 0x30, 0x10, 0x6D, 0x1C, 0x04, 0xEB, 0x41, 0x04, + 0x00, 0xEB, 0x41, 0x00, + 0x5D, 0x45, 0xD5, 0xDD, 0x96, 0xF8, 0x56, 0x02, 0x98, 0x42, 0x01, 0xD2, + 0x4F, 0xF0, 0x00, 0x0A, + 0x47, 0x48, 0x20, 0xF8, 0x33, 0x7F, 0x83, 0x70, 0x50, 0x46, 0x68, 0xE6, + 0x2D, 0xE9, 0xF0, 0x41, + 0x06, 0x46, 0x44, 0x48, 0x00, 0x24, 0x00, 0x78, 0xC0, 0x06, 0x5E, 0xD5, + 0x3C, 0x48, 0x36, 0x4D, + 0x00, 0x78, 0x88, 0xB1, 0x40, 0x48, 0x31, 0x4B, 0x34, 0x49, 0x02, 0x68, + 0x18, 0x68, 0x08, 0x31, + 0xB0, 0xF8, 0x5D, 0x02, 0x40, 0x42, 0x07, 0xB2, 0x00, 0x20, 0xC8, 0x80, + 0x88, 0x80, 0x08, 0x60, + 0x35, 0x48, 0xB0, 0xF9, 0x00, 0x00, 0x29, 0xE0, 0x2C, 0x48, 0x2C, 0x78, + 0x00, 0x78, 0x08, 0xB1, + 0x01, 0x29, 0x02, 0xD0, 0x08, 0x43, 0x02, 0xD0, 0x3B, 0xE0, 0x01, 0x24, + 0x3A, 0xE0, 0x00, 0x24, + 0x67, 0xE0, 0x00, 0xBF, 0x32, 0xF9, 0x10, 0xC0, 0xBC, 0xF1, 0x00, 0x0F, + 0x16, 0xDA, 0xB1, 0xF8, + 0x04, 0xC0, 0x0C, 0xF1, 0x01, 0x0C, 0xA1, 0xF8, 0x04, 0xC0, 0x32, 0xF9, + 0x10, 0xE0, 0xD1, 0xF8, + 0x00, 0xC0, 0xF4, 0x44, 0xC1, 0xF8, 0x00, 0xC0, 0x32, 0xF9, 0x10, 0xC0, + 0xBC, 0x45, 0x05, 0xDA, + 0xB1, 0xF8, 0x06, 0xC0, 0x0C, 0xF1, 0x01, 0x0C, 0xA1, 0xF8, 0x06, 0xC0, + 0x40, 0x1E, 0xE1, 0xD2, + 0x08, 0x68, 0x40, 0x42, 0x08, 0x60, 0x15, 0x48, 0x19, 0x68, 0x08, 0x30, + 0x02, 0x68, 0xB1, 0xF8, + 0x5F, 0x32, 0x9A, 0x42, 0x3D, 0xDD, 0xB0, 0xF9, 0x06, 0x00, 0x91, 0xF8, + 0x61, 0x12, 0x88, 0x42, + 0x37, 0xDD, 0x1A, 0x48, 0x11, 0x4A, 0xB0, 0xF9, 0x00, 0x10, 0x30, 0x46, + 0x00, 0xF0, 0x20, 0xF9, + 0x04, 0x46, 0x6C, 0xB3, 0x00, 0xF0, 0xF2, 0xF8, 0x2D, 0xE0, 0x3D, 0xE0, + 0xED, 0x06, 0x10, 0x00, + 0x94, 0x0B, 0x01, 0x20, 0xEE, 0x06, 0x10, 0x00, 0x9C, 0x06, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0x7E, 0x4A, 0x01, 0x20, 0xA8, 0x4A, 0x01, 0x20, 0x74, 0x05, 0x10, 0x00, + 0x64, 0x05, 0x10, 0x00, + 0x7A, 0x07, 0x10, 0x00, 0xF4, 0x06, 0x10, 0x00, 0x74, 0x07, 0x10, 0x00, + 0x40, 0x2B, 0x10, 0x00, + 0x79, 0x05, 0x10, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xFE, 0x06, 0x10, 0x00, + 0x50, 0x07, 0x10, 0x00, + 0x0A, 0x44, 0x01, 0x20, 0x04, 0x07, 0x10, 0x00, 0x14, 0x07, 0x10, 0x00, + 0x98, 0x06, 0x10, 0x00, + 0xFF, 0xE7, 0x00, 0xF0, 0xD9, 0xF8, 0x51, 0x4E, 0x28, 0x78, 0x31, 0x78, + 0x88, 0x42, 0x06, 0xD0, + 0x08, 0xB1, 0x01, 0x21, 0x00, 0xE0, 0x00, 0x21, 0x06, 0x20, 0x0B, 0xF0, + 0xEC, 0xF8, 0x28, 0x78, + 0x30, 0x70, 0x0C, 0xB1, 0x01, 0x20, 0xE4, 0xE5, 0x00, 0x20, 0xE2, 0xE5, + 0x70, 0xB5, 0x03, 0x20, + 0xF8, 0xF7, 0xBF, 0xFF, 0x00, 0xF0, 0x48, 0xF8, 0x04, 0x46, 0x03, 0x20, + 0xF8, 0xF7, 0xD4, 0xFF, + 0x43, 0x49, 0xC8, 0x7B, 0x64, 0xF3, 0x05, 0x10, 0xC8, 0x73, 0x42, 0x48, + 0x01, 0x78, 0x21, 0xB1, + 0x00, 0x21, 0x01, 0x70, 0x20, 0x46, 0x00, 0xF0, 0x30, 0xF9, 0x3F, 0x4D, + 0x3F, 0x48, 0x21, 0x46, + 0x2A, 0x78, 0x00, 0x68, 0xFF, 0xF7, 0x3A, 0xFF, 0xA8, 0x70, 0x70, 0xBD, + 0x2D, 0xE9, 0xF0, 0x47, + 0x1D, 0x46, 0x4F, 0xF0, 0x00, 0x08, 0xC5, 0xE9, 0x00, 0x88, 0x91, 0x46, + 0x82, 0x46, 0x0C, 0x46, + 0x11, 0xE0, 0x00, 0xBF, 0x3A, 0xF9, 0x14, 0x10, 0x49, 0x45, 0x0C, 0xDD, + 0xD5, 0xE9, 0x00, 0x67, + 0x4F, 0xF0, 0x01, 0x08, 0x22, 0x46, 0x40, 0x46, 0x00, 0x21, 0x0F, 0xF0, + 0x67, 0xFC, 0x06, 0x43, + 0x0F, 0x43, 0xC5, 0xE9, 0x00, 0x67, 0x64, 0x1E, 0xEC, 0xD2, 0x40, 0x46, + 0xBD, 0xE8, 0xF0, 0x87, + 0x2B, 0x48, 0x00, 0x21, 0xC0, 0xE9, 0x00, 0x11, 0xC0, 0xE9, 0x02, 0x11, + 0x08, 0x46, 0x29, 0x49, + 0x08, 0x76, 0x29, 0x49, 0x08, 0x76, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, + 0x27, 0x48, 0x00, 0x78, + 0x02, 0x28, 0x35, 0xD9, 0x26, 0x4E, 0x30, 0x68, 0x90, 0xF8, 0x50, 0x02, + 0x41, 0x07, 0x25, 0x48, + 0x00, 0x68, 0x02, 0xD5, 0x24, 0x49, 0x09, 0x78, 0x81, 0xB1, 0xFF, 0xF7, + 0x3C, 0xFE, 0x05, 0x46, + 0x30, 0x68, 0x90, 0xF8, 0x50, 0x02, 0x00, 0x07, 0x21, 0xD5, 0x22, 0x48, + 0x1F, 0x4B, 0x20, 0x49, + 0x02, 0x78, 0x02, 0x2A, 0x1B, 0xDB, 0x20, 0x4C, 0x50, 0x1E, 0x08, 0xE0, + 0xFF, 0xF7, 0x88, 0xFE, + 0xED, 0xE7, 0x00, 0xBF, 0x33, 0xF9, 0x10, 0x70, 0xA7, 0x42, 0x00, 0xDD, + 0x3C, 0x46, 0x40, 0x1E, + 0xF8, 0xD1, 0x98, 0x1C, 0x92, 0x1E, 0x0C, 0xF0, 0xC2, 0xFC, 0x31, 0x68, + 0x20, 0x1A, 0x00, 0xB2, + 0xB1, 0xF9, 0x57, 0x12, 0x88, 0x42, 0x02, 0xDD, 0x35, 0xB1, 0x02, 0x20, + 0x59, 0xE5, 0x0D, 0xB1, + 0x00, 0x20, 0x56, 0xE5, 0x01, 0x20, 0x54, 0xE5, 0x03, 0x20, 0x52, 0xE5, + 0x75, 0x05, 0x10, 0x00, + 0x0A, 0x44, 0x01, 0x20, 0x78, 0x05, 0x10, 0x00, 0x64, 0x05, 0x10, 0x00, + 0x14, 0x07, 0x10, 0x00, + 0x40, 0x2B, 0x10, 0x00, 0x18, 0x2A, 0x10, 0x00, 0x58, 0x2A, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x1C, 0x07, 0x10, 0x00, 0x79, 0x05, 0x10, 0x00, + 0xA8, 0x4A, 0x01, 0x20, + 0xCE, 0x0A, 0x01, 0x20, 0xEE, 0x06, 0x10, 0x00, 0x00, 0x80, 0xFF, 0xFF, + 0xFE, 0x48, 0x00, 0x21, + 0xC1, 0x70, 0x02, 0x78, 0x00, 0x2A, 0x0E, 0xD1, 0x82, 0x78, 0xFC, 0x4B, + 0x52, 0x1C, 0xD2, 0xB2, + 0x82, 0x70, 0x1B, 0x68, 0x93, 0xF8, 0x62, 0x32, 0x03, 0xF0, 0x0F, 0x03, + 0x93, 0x42, 0x02, 0xD2, + 0x01, 0x22, 0x02, 0x70, 0x81, 0x70, 0x70, 0x47, 0xF3, 0x48, 0x00, 0x21, + 0x81, 0x70, 0x02, 0x78, + 0x00, 0x2A, 0x0C, 0xD0, 0xC2, 0x78, 0xF1, 0x4B, 0x52, 0x1C, 0xD2, 0xB2, + 0xC2, 0x70, 0x1B, 0x68, + 0x93, 0xF8, 0x62, 0x32, 0xB2, 0xEB, 0x13, 0x1F, 0x01, 0xD9, 0x01, 0x70, + 0xC1, 0x70, 0x70, 0x47, + 0x2D, 0xE9, 0xF7, 0x4F, 0x86, 0xB0, 0x8A, 0x46, 0xD2, 0xE9, 0x00, 0x01, + 0xCD, 0xE9, 0x00, 0x01, + 0xD2, 0xE9, 0x02, 0x01, 0xCD, 0xE9, 0x04, 0x01, 0x68, 0x46, 0x0F, 0xF0, + 0x61, 0xFD, 0x04, 0xA8, + 0x0F, 0xF0, 0x5E, 0xFD, 0xE2, 0x48, 0x00, 0x27, 0xB9, 0x46, 0x06, 0x78, + 0x28, 0xE0, 0xF1, 0xB2, + 0x06, 0x98, 0x0F, 0xF0, 0x6B, 0xFD, 0x80, 0x46, 0xDE, 0x48, 0xDD, 0xE9, + 0x04, 0xB1, 0x05, 0x78, + 0x01, 0x24, 0x00, 0x98, 0xB4, 0x40, 0x04, 0x40, 0x02, 0x91, 0x17, 0xE0, + 0x38, 0xF9, 0x15, 0x10, + 0x51, 0x45, 0x13, 0xDD, 0x20, 0x00, 0x0F, 0xD0, 0x2A, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x0F, 0xF0, + 0x95, 0xFB, 0x02, 0x9A, 0x00, 0xEA, 0x0B, 0x00, 0x11, 0x40, 0x08, 0x43, + 0x04, 0xD0, 0x09, 0xF1, + 0x01, 0x00, 0x1F, 0xFA, 0x80, 0xF9, 0x01, 0xE0, 0x7F, 0x1C, 0xBF, 0xB2, + 0x6D, 0x1E, 0xE5, 0xD2, + 0x76, 0x1E, 0xD4, 0xD2, 0xC9, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x5B, 0x12, + 0xB9, 0x42, 0x07, 0xD8, + 0x90, 0xF8, 0x5C, 0x12, 0x49, 0x45, 0x03, 0xD3, 0x01, 0x20, 0x09, 0xB0, + 0xBD, 0xE8, 0xF0, 0x8F, + 0x00, 0x20, 0xFA, 0xE7, 0xC0, 0x48, 0x10, 0xB5, 0x41, 0x78, 0x01, 0x70, + 0x00, 0x21, 0x81, 0x70, + 0xC1, 0x70, 0xFF, 0xF7, 0x1A, 0xFD, 0xBD, 0xE8, 0x10, 0x40, 0xFE, 0xF7, + 0x59, 0xBE, 0xBA, 0x48, + 0x00, 0x21, 0xBA, 0x4A, 0x01, 0x70, 0x41, 0x70, 0x12, 0x68, 0x92, 0xF8, + 0x50, 0x22, 0x92, 0x07, + 0x00, 0xD5, 0x01, 0x21, 0x41, 0x71, 0x01, 0x71, 0x70, 0x47, 0xB3, 0x49, + 0x4A, 0x79, 0x01, 0x2A, + 0x02, 0xD1, 0x00, 0x28, 0x00, 0xD1, 0x48, 0x71, 0x70, 0x47, 0xF0, 0xB5, + 0x00, 0x24, 0x1C, 0x72, + 0x04, 0x7E, 0x0D, 0x7E, 0x6C, 0x43, 0x04, 0xF0, 0xFF, 0x0C, 0x4F, 0xF0, + 0xFF, 0x34, 0xE7, 0x07, + 0x26, 0x46, 0x00, 0x25, 0x08, 0xE0, 0x00, 0xBF, 0x52, 0xF8, 0x25, 0xE0, + 0xBE, 0x45, 0x01, 0xDD, + 0x77, 0x46, 0x6E, 0xB2, 0x6D, 0x1C, 0xED, 0xB2, 0x65, 0x45, 0xF5, 0xD3, + 0x00, 0x2E, 0x17, 0xDB, + 0x01, 0x25, 0x1D, 0x72, 0x0D, 0x7E, 0x96, 0xFB, 0xF5, 0xF5, 0x6D, 0x1C, + 0xED, 0xB2, 0x05, 0x44, + 0xAF, 0x7C, 0x1F, 0x70, 0x2D, 0x7B, 0x1D, 0x71, 0x0D, 0x7E, 0x96, 0xFB, + 0xF5, 0xF7, 0x05, 0xFB, + 0x17, 0x65, 0x6D, 0x1C, 0xED, 0xB2, 0x0D, 0x44, 0xAF, 0x7C, 0x9F, 0x70, + 0x2D, 0x7B, 0x9D, 0x71, + 0xBC, 0xF1, 0x01, 0x0F, 0x30, 0xD9, 0x95, 0x4D, 0x2D, 0x68, 0x95, 0xF8, + 0x51, 0x52, 0xED, 0x07, + 0x2A, 0xD0, 0x25, 0x46, 0x00, 0x27, 0x3C, 0x46, 0x0A, 0xE0, 0x00, 0xBF, + 0x52, 0xF8, 0x24, 0xE0, + 0xBE, 0x45, 0x03, 0xDD, 0xA6, 0x42, 0x01, 0xD0, 0x77, 0x46, 0x65, 0xB2, + 0x64, 0x1C, 0xE4, 0xB2, + 0x64, 0x45, 0xF3, 0xD3, 0x00, 0x2D, 0x17, 0xDB, 0x02, 0x22, 0x1A, 0x72, + 0x0A, 0x7E, 0x95, 0xFB, + 0xF2, 0xF2, 0x52, 0x1C, 0xD2, 0xB2, 0x10, 0x44, 0x82, 0x7C, 0x5A, 0x70, + 0x00, 0x7B, 0x58, 0x71, + 0x08, 0x7E, 0x95, 0xFB, 0xF0, 0xF2, 0x00, 0xFB, 0x12, 0x50, 0x40, 0x1C, + 0xC0, 0xB2, 0x08, 0x44, + 0x81, 0x7C, 0xD9, 0x70, 0x00, 0x7B, 0xD8, 0x71, 0xF0, 0xBD, 0x2D, 0xE9, + 0xFF, 0x47, 0x0F, 0x46, + 0x06, 0x46, 0xD2, 0xE9, 0x00, 0x01, 0xCD, 0xE9, 0x00, 0x01, 0xD2, 0xE9, + 0x02, 0x01, 0xCD, 0xE9, + 0x02, 0x01, 0x68, 0x46, 0x0F, 0xF0, 0x84, 0xFC, 0x02, 0xA8, 0x0F, 0xF0, + 0x81, 0xFC, 0x00, 0x25, + 0xDF, 0xF8, 0xD0, 0x91, 0xDF, 0xF8, 0xC8, 0x81, 0x2F, 0xE0, 0x2A, 0x46, + 0x01, 0x20, 0x00, 0x21, + 0x0F, 0xF0, 0xCC, 0xFA, 0xDD, 0xE9, 0x00, 0x23, 0x10, 0x40, 0x19, 0x40, + 0x08, 0x43, 0x01, 0xD0, + 0x00, 0x24, 0x17, 0xE0, 0x99, 0xF8, 0x00, 0x00, 0x39, 0x46, 0x42, 0x00, + 0x30, 0x46, 0x0F, 0xF0, + 0xF4, 0xFA, 0x13, 0xE0, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x0F, 0xF0, + 0xB7, 0xFA, 0xDD, 0xE9, + 0x02, 0x23, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x03, 0xD1, 0x37, 0xF8, + 0x14, 0x00, 0x26, 0xF8, + 0x14, 0x00, 0x64, 0x1C, 0x99, 0xF8, 0x00, 0x00, 0x84, 0x42, 0xEB, 0xDB, + 0x99, 0xF8, 0x00, 0x00, + 0x6D, 0x1C, 0x07, 0xEB, 0x40, 0x07, 0x06, 0xEB, 0x40, 0x06, 0x98, 0xF8, + 0x00, 0x00, 0x85, 0x42, + 0xCB, 0xDB, 0xBD, 0xE8, 0xFF, 0x87, 0x2D, 0xE9, 0xFF, 0x4F, 0x81, 0x46, + 0x84, 0x1C, 0x80, 0x78, + 0x81, 0xB0, 0x9A, 0x46, 0x15, 0x46, 0x60, 0xB1, 0x40, 0x1E, 0xC2, 0xB2, + 0x22, 0x70, 0xD5, 0xE9, + 0x00, 0x67, 0x01, 0x20, 0x00, 0x21, 0x0F, 0xF0, 0x89, 0xFA, 0x06, 0x43, + 0x0F, 0x43, 0xC5, 0xE9, + 0x00, 0x67, 0x4F, 0xF0, 0x01, 0x08, 0xAA, 0xF1, 0x01, 0x0A, 0x2D, 0xE0, + 0x09, 0xEB, 0x48, 0x00, + 0x00, 0xF1, 0x02, 0x0B, 0x82, 0x78, 0x60, 0x78, 0xC1, 0x1C, 0x8A, 0x42, + 0x1F, 0xD9, 0x50, 0x45, + 0x0C, 0xDA, 0x40, 0x1C, 0xC2, 0xB2, 0x62, 0x70, 0xD5, 0xE9, 0x00, 0x76, + 0x01, 0x20, 0x00, 0x21, + 0x0F, 0xF0, 0x6C, 0xFA, 0x07, 0x43, 0x0E, 0x43, 0xC5, 0xE9, 0x00, 0x76, + 0x9B, 0xF8, 0x00, 0x00, + 0x68, 0xB1, 0x40, 0x1E, 0x8B, 0xF8, 0x00, 0x00, 0x22, 0x78, 0xD5, 0xE9, + 0x00, 0x67, 0x01, 0x20, + 0x00, 0x21, 0x0F, 0xF0, 0x5B, 0xFA, 0x06, 0x43, 0x0F, 0x43, 0xC5, 0xE9, + 0x00, 0x67, 0x08, 0xF1, + 0x01, 0x00, 0x5C, 0x46, 0x00, 0xF0, 0xFF, 0x08, 0x99, 0xF8, 0x18, 0x00, + 0x40, 0x45, 0xCD, 0xD8, + 0x60, 0x78, 0x50, 0x45, 0x0C, 0xDA, 0x40, 0x1C, 0xC2, 0xB2, 0x62, 0x70, + 0xD5, 0xE9, 0x00, 0x46, + 0x01, 0x20, 0x00, 0x21, 0x0F, 0xF0, 0x42, 0xFA, 0x04, 0x43, 0x0E, 0x43, + 0xC5, 0xE9, 0x00, 0x46, + 0x01, 0x20, 0x04, 0x46, 0x00, 0x90, 0x66, 0xE0, 0x02, 0x98, 0x22, 0x46, + 0x00, 0x21, 0xD0, 0xE9, + 0x00, 0x67, 0x01, 0x20, 0x0F, 0xF0, 0x32, 0xFA, 0x80, 0x46, 0x8B, 0x46, + 0x06, 0xEA, 0x08, 0x06, + 0x07, 0xEA, 0x0B, 0x07, 0x3E, 0x43, 0x27, 0xD0, 0xD5, 0xE9, 0x00, 0x67, + 0x46, 0xEA, 0x08, 0x06, + 0x47, 0xEA, 0x0B, 0x07, 0x62, 0x1E, 0x01, 0x20, 0x00, 0x21, 0xC5, 0xE9, + 0x00, 0x67, 0x0F, 0xF0, + 0x1D, 0xFA, 0x06, 0x40, 0x0F, 0x40, 0x3E, 0x43, 0x05, 0xD0, 0x00, 0x99, + 0x09, 0xEB, 0x41, 0x00, + 0x41, 0x78, 0x49, 0x1C, 0x41, 0x70, 0xD5, 0xE9, 0x00, 0x67, 0x62, 0x1C, + 0x01, 0x20, 0x00, 0x21, + 0x0F, 0xF0, 0x0C, 0xFA, 0x06, 0x40, 0x0F, 0x40, 0x3E, 0x43, 0x05, 0xD0, + 0x00, 0x99, 0x09, 0xEB, + 0x41, 0x01, 0x88, 0x78, 0x40, 0x1E, 0x88, 0x70, 0xD5, 0xE9, 0x00, 0x67, + 0x62, 0x1E, 0x01, 0x20, + 0x00, 0x21, 0x0F, 0xF0, 0xFB, 0xF9, 0x30, 0x40, 0x39, 0x40, 0x08, 0x43, + 0x21, 0xD0, 0x58, 0xEA, + 0x0B, 0x01, 0x0F, 0xD0, 0x00, 0x20, 0x07, 0xE0, 0x74, 0x05, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, 0x06, 0x40, 0x07, 0xEA, + 0xE0, 0x77, 0x3E, 0x43, + 0x0B, 0xD1, 0x01, 0xE0, 0x01, 0x20, 0xEE, 0xE7, 0x02, 0x99, 0xD1, 0xE9, + 0x00, 0x01, 0x00, 0xEA, + 0x08, 0x00, 0x01, 0xEA, 0x0B, 0x01, 0x08, 0x43, 0x03, 0xD0, 0x00, 0x98, + 0x40, 0x1C, 0xC0, 0xB2, + 0x00, 0x90, 0x64, 0x1C, 0xE4, 0xB2, 0x54, 0x45, 0x96, 0xDB, 0x05, 0xB0, + 0x56, 0xE6, 0x2D, 0xE9, + 0xFF, 0x5F, 0x05, 0x46, 0xFE, 0x49, 0xDD, 0xF8, 0x38, 0xB0, 0x00, 0x20, + 0x05, 0xEB, 0x40, 0x03, + 0x40, 0x1C, 0x0C, 0x88, 0xC0, 0xB2, 0x1C, 0x80, 0x06, 0x28, 0xF7, 0xD3, + 0x00, 0x20, 0x28, 0x73, + 0xF8, 0x48, 0x00, 0x68, 0xB0, 0xF9, 0x6E, 0x82, 0xB2, 0xF9, 0x08, 0x00, + 0x40, 0x45, 0x02, 0xDB, + 0xB8, 0xF1, 0x00, 0x0F, 0x00, 0xD1, 0x80, 0x46, 0x4F, 0xF0, 0x01, 0x0A, + 0x00, 0x24, 0x28, 0xE0, + 0x03, 0x98, 0x05, 0xEB, 0x4A, 0x09, 0x22, 0x46, 0xD0, 0xE9, 0x00, 0x67, + 0x01, 0x20, 0x00, 0x21, + 0x0F, 0xF0, 0xA4, 0xF9, 0x06, 0x40, 0x0F, 0x40, 0x3E, 0x43, 0x04, 0xD1, + 0x01, 0x98, 0x30, 0xF9, + 0x14, 0x10, 0x41, 0x45, 0x0B, 0xDD, 0x99, 0xF8, 0x00, 0x00, 0xFF, 0x28, + 0x04, 0xD1, 0x89, 0xF8, + 0x00, 0x40, 0x28, 0x7B, 0x40, 0x1C, 0x28, 0x73, 0x89, 0xF8, 0x01, 0x40, + 0x07, 0xE0, 0x99, 0xF8, + 0x00, 0x00, 0xFF, 0x28, 0x03, 0xD0, 0x0A, 0xF1, 0x01, 0x00, 0x00, 0xF0, + 0xFF, 0x0A, 0x64, 0x1C, + 0xE4, 0xB2, 0x5C, 0x45, 0xD4, 0xD3, 0xBD, 0xE8, 0xFF, 0x9F, 0x2D, 0xE9, + 0xFF, 0x4F, 0x85, 0xB0, + 0x00, 0x20, 0x05, 0x46, 0x02, 0x90, 0x04, 0x90, 0xD7, 0x48, 0x9B, 0x46, + 0x8A, 0x46, 0x06, 0x68, + 0x01, 0x20, 0x81, 0x46, 0x05, 0x98, 0x01, 0x7E, 0x49, 0x45, 0x7D, 0xD3, + 0x05, 0x98, 0x01, 0x27, + 0x10, 0xF8, 0x19, 0x10, 0x40, 0x46, 0x61, 0xF3, 0x17, 0x40, 0x05, 0x99, + 0x01, 0xEB, 0x49, 0x01, + 0x49, 0x78, 0x61, 0xF3, 0x1F, 0x60, 0x80, 0x46, 0x69, 0xE0, 0x00, 0xBF, + 0x1A, 0xF8, 0x17, 0x10, + 0x40, 0x46, 0x61, 0xF3, 0x07, 0x00, 0x0A, 0xEB, 0x47, 0x01, 0x01, 0x23, + 0x49, 0x78, 0x61, 0xF3, + 0x0F, 0x20, 0x80, 0x46, 0x00, 0x20, 0x86, 0xF8, 0x0E, 0x01, 0x02, 0x46, + 0xC3, 0x48, 0xC6, 0xF8, + 0x00, 0x80, 0x44, 0x46, 0x31, 0x46, 0x00, 0x68, 0x06, 0xF0, 0x62, 0xFF, + 0x0B, 0xEB, 0x85, 0x00, + 0x44, 0x66, 0x00, 0x20, 0x4B, 0xF8, 0x25, 0x00, 0x4F, 0xF0, 0x00, 0x40, + 0x01, 0x90, 0x00, 0x20, + 0x01, 0x24, 0x03, 0x90, 0x3C, 0xE0, 0x00, 0xBF, 0x06, 0xEB, 0x44, 0x00, + 0xB0, 0xF8, 0xB4, 0x10, + 0x07, 0x98, 0x81, 0x42, 0x2D, 0xD9, 0xB6, 0x48, 0x06, 0xEB, 0x84, 0x03, + 0xE2, 0xB2, 0x01, 0x68, + 0xB2, 0x48, 0x00, 0x68, 0xFE, 0xF7, 0x7A, 0xFE, 0x01, 0x99, 0x00, 0x90, + 0x88, 0x42, 0x0F, 0xDD, + 0x03, 0x98, 0x48, 0xB1, 0xC1, 0xB2, 0xAD, 0x48, 0x32, 0x46, 0x00, 0x68, + 0x07, 0xF0, 0x2D, 0xF8, + 0x02, 0x98, 0x40, 0x1E, 0xC0, 0xB2, 0x02, 0x90, 0x00, 0x98, 0x01, 0x90, + 0x60, 0xB2, 0x03, 0x90, + 0x5B, 0xF8, 0x25, 0x10, 0x00, 0x98, 0x01, 0x44, 0x4B, 0xF8, 0x25, 0x10, + 0x02, 0x98, 0x04, 0x99, + 0x40, 0x1C, 0xC0, 0xB2, 0x02, 0x90, 0x01, 0x20, 0xA8, 0x40, 0x08, 0x43, + 0x80, 0xB2, 0x04, 0x90, + 0x05, 0xE0, 0x9E, 0x48, 0xE1, 0xB2, 0x32, 0x46, 0x00, 0x68, 0x07, 0xF0, + 0x0E, 0xF8, 0x64, 0x1C, + 0x96, 0xF8, 0x0E, 0x01, 0xA0, 0x42, 0xBF, 0xD2, 0x6D, 0x1C, 0xED, 0xB2, + 0x7F, 0x1C, 0x9A, 0xF8, + 0x18, 0x00, 0xB8, 0x42, 0x92, 0xD2, 0x00, 0xE0, 0x02, 0xE0, 0x09, 0xF1, + 0x01, 0x00, 0x78, 0xE7, + 0x94, 0x48, 0x04, 0x99, 0xA0, 0xF8, 0x19, 0x10, 0x02, 0x98, 0x6E, 0xE5, + 0x2D, 0xE9, 0xFF, 0x5F, + 0xDF, 0xF8, 0x44, 0x92, 0x91, 0x4E, 0x09, 0xF1, 0x20, 0x00, 0x03, 0x90, + 0x06, 0xF1, 0x20, 0x00, + 0x02, 0x90, 0x90, 0x49, 0x8E, 0x48, 0xDF, 0xF8, 0x40, 0xB2, 0x1E, 0xC9, + 0x80, 0xE8, 0x1E, 0x00, + 0x8E, 0x49, 0x00, 0x20, 0x8B, 0xF8, 0x00, 0x00, 0x08, 0x72, 0x82, 0x48, + 0x31, 0x7E, 0x00, 0x68, + 0x90, 0xF8, 0x51, 0x02, 0x00, 0xF0, 0x01, 0x08, 0x99, 0xF8, 0x18, 0x00, + 0xC8, 0x42, 0x05, 0xD1, + 0x43, 0x46, 0x83, 0x4A, 0x31, 0x46, 0x48, 0x46, 0xFE, 0xF7, 0x3E, 0xFD, + 0x99, 0xF8, 0x18, 0x40, + 0x37, 0x7E, 0x04, 0xFB, 0x07, 0xF0, 0x10, 0xF0, 0xFF, 0x05, 0x77, 0xD0, + 0x19, 0x2D, 0x75, 0xD2, + 0x05, 0x2C, 0x73, 0xD8, 0x05, 0x2F, 0x71, 0xD8, 0x79, 0x48, 0xFC, 0x21, + 0x10, 0x30, 0x0F, 0xF0, + 0x85, 0xF9, 0x77, 0x48, 0x39, 0x46, 0x10, 0x30, 0x80, 0xF8, 0xFA, 0x50, + 0x20, 0x46, 0x0B, 0xF0, + 0x67, 0xF9, 0x00, 0xF0, 0xFF, 0x0A, 0x72, 0x48, 0x08, 0x30, 0x01, 0x90, + 0xB8, 0xF1, 0x00, 0x0F, + 0x0D, 0xD0, 0x73, 0x48, 0x6E, 0x4A, 0x03, 0x99, 0x03, 0x78, 0x48, 0x46, + 0xFF, 0xF7, 0xFB, 0xFD, + 0x70, 0x48, 0xDD, 0xE9, 0x01, 0x21, 0x03, 0x78, 0x30, 0x46, 0xFF, 0xF7, + 0xF4, 0xFD, 0x6E, 0x48, + 0x00, 0x90, 0x6E, 0x48, 0x66, 0x49, 0xB0, 0xF9, 0x00, 0x30, 0x60, 0x48, + 0x02, 0x68, 0x60, 0x48, + 0x00, 0x68, 0xFE, 0xF7, 0x5A, 0xFD, 0x6A, 0x49, 0x5A, 0x4F, 0x61, 0x4B, + 0x08, 0x60, 0x38, 0x68, + 0x10, 0x33, 0x31, 0x46, 0x90, 0xF8, 0x6D, 0x22, 0x48, 0x46, 0xFF, 0xF7, + 0xF6, 0xFE, 0x04, 0x46, + 0x38, 0x68, 0x90, 0xF8, 0x51, 0x02, 0x80, 0x07, 0x28, 0xD5, 0x5D, 0x48, + 0xDF, 0xF8, 0x58, 0x81, + 0x56, 0x4F, 0x00, 0x78, 0x08, 0xF1, 0x30, 0x08, 0x00, 0x90, 0x30, 0x37, + 0x54, 0x4B, 0x5D, 0x49, + 0x40, 0x46, 0x03, 0x9A, 0xFF, 0xF7, 0x93, 0xFE, 0x56, 0x48, 0x5B, 0x49, + 0x00, 0x78, 0x00, 0x90, + 0xDD, 0xE9, 0x01, 0x32, 0x38, 0x46, 0xFF, 0xF7, 0x8A, 0xFE, 0x4A, 0x48, + 0x98, 0xF8, 0x0C, 0x20, + 0x81, 0x7D, 0x62, 0xF3, 0x03, 0x01, 0x81, 0x75, 0x3A, 0x7B, 0x62, 0xF3, + 0x07, 0x11, 0x81, 0x75, + 0x47, 0x4A, 0x39, 0x46, 0x10, 0x32, 0x40, 0x46, 0x00, 0xF0, 0x3A, 0xF8, + 0xA2, 0x45, 0x06, 0xD8, + 0xAC, 0x42, 0x04, 0xD8, 0x01, 0x21, 0x8B, 0xF8, 0x00, 0x10, 0x0A, 0xE0, + 0x10, 0xE0, 0x00, 0x20, + 0x3F, 0x4A, 0x8B, 0xF8, 0x00, 0x00, 0x41, 0x4B, 0x10, 0x32, 0x31, 0x46, + 0x48, 0x46, 0xFF, 0xF7, + 0xE4, 0xFC, 0x38, 0x48, 0x01, 0x7E, 0x6A, 0xF3, 0x03, 0x01, 0x64, 0xF3, + 0x07, 0x11, 0x01, 0x76, + 0xA9, 0xE6, 0x10, 0xB5, 0x01, 0x21, 0x31, 0x48, 0x08, 0xF0, 0x31, 0xFD, + 0x02, 0x21, 0x3F, 0x48, + 0x08, 0xF0, 0xD5, 0xFC, 0x04, 0x21, 0x2C, 0x48, 0x08, 0xF0, 0xD1, 0xFC, + 0xFF, 0xF7, 0x36, 0xFF, + 0xFE, 0xF7, 0x2D, 0xFE, 0x02, 0x21, 0x39, 0x48, 0x08, 0xF0, 0xE6, 0xFC, + 0x04, 0x21, 0x26, 0x48, + 0x08, 0xF0, 0xE2, 0xFC, 0xBD, 0xE8, 0x10, 0x40, 0x01, 0x21, 0x24, 0x48, + 0x08, 0xF0, 0xAA, 0xBD, + 0x2D, 0xE9, 0xF0, 0x47, 0x14, 0x46, 0x0D, 0x46, 0x06, 0x46, 0x00, 0xF0, + 0x8B, 0xF8, 0x30, 0x7B, + 0x29, 0x7B, 0x1C, 0x4F, 0x48, 0x43, 0xC5, 0xB2, 0x01, 0x20, 0x30, 0xE0, + 0x00, 0x21, 0x0A, 0x46, + 0x94, 0xF8, 0xFA, 0x60, 0x0C, 0xE0, 0x00, 0xBF, 0x54, 0xF8, 0x22, 0x30, + 0x8B, 0x42, 0x06, 0xDD, + 0x04, 0xEB, 0x02, 0x0C, 0x9C, 0xF8, 0xE1, 0xC0, 0x84, 0x45, 0x00, 0xD1, + 0x19, 0x46, 0x52, 0x1C, + 0x96, 0x42, 0xF1, 0xD8, 0x3A, 0x68, 0xB2, 0xF8, 0x70, 0x22, 0x8A, 0x42, + 0x15, 0xDA, 0x00, 0x22, + 0x0F, 0xE0, 0xA3, 0x18, 0x93, 0xF8, 0xE1, 0x60, 0x86, 0x42, 0x09, 0xD1, + 0x54, 0xF8, 0x22, 0x60, + 0x4F, 0xF0, 0x64, 0x0C, 0x06, 0xFB, 0x0C, 0xF6, 0x96, 0xFB, 0xF1, 0xF6, + 0x83, 0xF8, 0xC8, 0x60, + 0x52, 0x1C, 0x94, 0xF8, 0xFA, 0x30, 0x93, 0x42, 0xEB, 0xD8, 0x40, 0x1C, + 0xC0, 0xB2, 0x27, 0xE0, + 0xFC, 0x78, 0x01, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x58, 0x05, 0x10, 0x00, + 0x50, 0x06, 0x10, 0x00, + 0x14, 0x07, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, 0x18, 0x2A, 0x10, 0x00, + 0x58, 0x2A, 0x10, 0x00, + 0x60, 0x2B, 0x10, 0x00, 0x40, 0x2B, 0x10, 0x00, 0x57, 0x05, 0x10, 0x00, + 0x0C, 0x2A, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, 0x84, 0x06, 0x10, 0x00, + 0x92, 0x06, 0x10, 0x00, + 0x7C, 0x06, 0x10, 0x00, 0x94, 0x0B, 0x01, 0x20, 0xBE, 0x0B, 0x01, 0x20, + 0x60, 0x06, 0x10, 0x00, + 0xA8, 0x42, 0xA3, 0xD9, 0x00, 0x26, 0x35, 0x46, 0xB8, 0x46, 0xB1, 0x46, + 0xDF, 0xF8, 0xD4, 0xA0, + 0x18, 0xE0, 0xD8, 0xF8, 0x00, 0x00, 0x67, 0x19, 0x97, 0xF8, 0xC8, 0x10, + 0x90, 0xF8, 0x72, 0x02, + 0x81, 0x42, 0x0E, 0xD2, 0x04, 0xEB, 0x85, 0x01, 0x00, 0x22, 0x64, 0x31, + 0xDA, 0xF8, 0x00, 0x00, + 0x06, 0xF0, 0xCE, 0xFC, 0x44, 0xF8, 0x25, 0x90, 0x97, 0xF8, 0xC8, 0x00, + 0xB0, 0x42, 0x00, 0xD2, + 0x06, 0x46, 0x6D, 0x1C, 0x94, 0xF8, 0xFA, 0x00, 0xA8, 0x42, 0xE2, 0xD8, + 0x26, 0x48, 0xC6, 0x75, + 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xF8, 0x4F, 0x82, 0x46, 0x01, 0x24, + 0x16, 0x46, 0x0F, 0x46, + 0x20, 0x46, 0x9A, 0xF8, 0x0C, 0x10, 0x81, 0x46, 0x49, 0x45, 0x38, 0xD3, + 0x1A, 0xF8, 0x14, 0x00, + 0x8D, 0xF8, 0x02, 0x00, 0x0A, 0xEB, 0x44, 0x00, 0x40, 0x78, 0x8D, 0xF8, + 0x03, 0x00, 0x01, 0x20, + 0x26, 0xE0, 0x00, 0xBF, 0x17, 0xF8, 0x14, 0x00, 0x8D, 0xF8, 0x00, 0x00, + 0x07, 0xEB, 0x44, 0x00, + 0x00, 0x25, 0x40, 0x78, 0x8D, 0xF8, 0x01, 0x00, 0x12, 0xE0, 0x00, 0xBF, + 0x06, 0xEB, 0x05, 0x0B, + 0x9B, 0xF8, 0xE1, 0x00, 0x58, 0xB9, 0x06, 0xEB, 0x85, 0x01, 0x68, 0x46, + 0x64, 0x31, 0x06, 0xF0, + 0x7B, 0xFC, 0x20, 0xB1, 0x8B, 0xF8, 0xE1, 0x40, 0x64, 0x20, 0x8B, 0xF8, + 0xC8, 0x00, 0x6D, 0x1C, + 0x96, 0xF8, 0xFA, 0x00, 0xA8, 0x42, 0xE9, 0xD8, 0x64, 0x1C, 0xE4, 0xB2, + 0x08, 0xF1, 0x01, 0x00, + 0x39, 0x7B, 0x80, 0x46, 0x41, 0x45, 0xD5, 0xD2, 0x09, 0xF1, 0x01, 0x00, + 0xC1, 0xE7, 0xBD, 0xE8, + 0xF8, 0x8F, 0x00, 0x00, 0x50, 0x06, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, + 0x2D, 0xE9, 0xFF, 0x4F, + 0xCE, 0x4B, 0x83, 0xB0, 0x1B, 0x68, 0xB3, 0xF9, 0xC2, 0x42, 0xB3, 0xF9, + 0xC4, 0xE2, 0x99, 0xE0, + 0x47, 0xF6, 0xFF, 0x76, 0xF7, 0x43, 0x06, 0x9D, 0x08, 0xE0, 0x00, 0xBF, + 0x31, 0xF9, 0x15, 0x30, + 0xB3, 0x42, 0x00, 0xDA, 0x1E, 0x46, 0xBB, 0x42, 0x00, 0xDD, 0x1F, 0x46, + 0x6D, 0x1E, 0xF5, 0xD1, + 0xAB, 0x46, 0x00, 0x2F, 0x01, 0xDA, 0xBB, 0x46, 0x02, 0xE0, 0x00, 0x2E, + 0x00, 0xDD, 0xB3, 0x46, + 0x00, 0x26, 0x37, 0x46, 0xB2, 0x46, 0x35, 0x46, 0xB1, 0x46, 0x06, 0x9B, + 0x13, 0xE0, 0x00, 0xBF, + 0x31, 0xF9, 0x13, 0x80, 0xA8, 0xEB, 0x0B, 0x0C, 0xA4, 0x45, 0x0C, 0xDA, + 0x0C, 0xEB, 0x04, 0x08, + 0xB8, 0xF1, 0x00, 0x0F, 0x07, 0xDD, 0x03, 0xFB, 0x03, 0x77, 0x03, 0xFB, + 0x0C, 0x55, 0x1E, 0x44, + 0xE2, 0x44, 0x09, 0xF1, 0x01, 0x09, 0x5B, 0x1E, 0xEA, 0xD1, 0x07, 0xFB, + 0x09, 0xF3, 0x06, 0xFB, + 0x16, 0x33, 0x02, 0x93, 0x05, 0xFB, 0x09, 0xF3, 0x06, 0xFB, 0x1A, 0x33, + 0x07, 0xFB, 0x0A, 0xF7, + 0x01, 0x93, 0x05, 0xFB, 0x16, 0x73, 0x4F, 0xF0, 0x00, 0x0C, 0x00, 0x93, + 0x67, 0x46, 0x66, 0x46, + 0xE2, 0x46, 0x06, 0x9B, 0x28, 0xE0, 0xDD, 0xF8, 0x08, 0x80, 0x00, 0x25, + 0xB8, 0xF1, 0x00, 0x0F, + 0x0D, 0xD0, 0xDD, 0xE9, 0x00, 0x58, 0x08, 0xFB, 0x03, 0x58, 0x02, 0x9D, + 0x98, 0xFB, 0xF5, 0xF5, + 0xA5, 0x42, 0x01, 0xDD, 0x25, 0x46, 0x02, 0xE0, 0xE5, 0x42, 0x00, 0xD5, + 0x65, 0x42, 0x31, 0xF8, + 0x13, 0x80, 0x5D, 0x44, 0xA8, 0xEB, 0x05, 0x05, 0x2D, 0xB2, 0x7F, 0x1C, + 0xA9, 0x46, 0xAC, 0x44, + 0x75, 0x45, 0x07, 0xDA, 0x05, 0xEB, 0x0E, 0x08, 0xB8, 0xF1, 0x00, 0x0F, + 0x02, 0xDD, 0x4E, 0x44, + 0x0A, 0xF1, 0x01, 0x0A, 0x20, 0xF8, 0x13, 0x90, 0x5B, 0x1E, 0xD4, 0xD1, + 0x9C, 0xFB, 0xF7, 0xF5, + 0xBA, 0xF1, 0x00, 0x0F, 0x01, 0xD1, 0x4F, 0xF0, 0x01, 0x0A, 0x96, 0xFB, + 0xFA, 0xF3, 0x00, 0x2D, + 0x01, 0xDB, 0x2F, 0x46, 0x00, 0xE0, 0x6F, 0x42, 0x1E, 0x1E, 0x00, 0xDA, + 0x5E, 0x42, 0xB7, 0xEB, + 0x46, 0x0F, 0x00, 0xDD, 0x1D, 0x46, 0x06, 0x9B, 0x05, 0xE0, 0x00, 0xBF, + 0x30, 0xF8, 0x13, 0x60, + 0x76, 0x1B, 0x20, 0xF8, 0x13, 0x60, 0x5B, 0x1E, 0xF8, 0xD1, 0x06, 0x9B, + 0x01, 0xEB, 0x43, 0x01, + 0x00, 0xEB, 0x43, 0x00, 0x52, 0x1E, 0xBF, 0xF4, 0x63, 0xAF, 0x07, 0xB0, + 0xBD, 0xE8, 0xF0, 0x8F, + 0x2D, 0xE9, 0xF7, 0x4F, 0x79, 0x4D, 0x7A, 0x4C, 0x7A, 0x4F, 0x28, 0x68, + 0x0E, 0x46, 0x90, 0xF8, + 0xC0, 0x02, 0xC0, 0x07, 0x00, 0xD0, 0x3C, 0x68, 0x03, 0x20, 0xF8, 0xF7, + 0x9A, 0xF9, 0x77, 0x48, + 0xDF, 0xF8, 0xD4, 0xB1, 0x31, 0x46, 0x02, 0x68, 0xBB, 0xF9, 0x00, 0x30, + 0x20, 0x46, 0x0B, 0xF0, + 0xB0, 0xFE, 0x03, 0x20, 0xF8, 0xF7, 0xA8, 0xF9, 0x28, 0x68, 0xDF, 0xF8, + 0xC4, 0xA1, 0x71, 0x4E, + 0x90, 0xF8, 0xC0, 0x02, 0xC0, 0x07, 0x06, 0xD0, 0x9A, 0xF8, 0x00, 0x30, + 0x32, 0x78, 0x21, 0x46, + 0x67, 0x48, 0xFF, 0xF7, 0x2B, 0xFF, 0xB9, 0x46, 0x65, 0x4A, 0x33, 0x78, + 0x4F, 0xF0, 0x00, 0x08, + 0x54, 0x46, 0x38, 0x68, 0x16, 0xE0, 0x00, 0xBF, 0xA0, 0xF8, 0x00, 0x80, + 0x01, 0x21, 0x09, 0xE0, + 0x00, 0xEB, 0x41, 0x07, 0x32, 0xF8, 0x11, 0xC0, 0x37, 0xF8, 0x02, 0x7C, + 0x67, 0x44, 0x20, 0xF8, + 0x11, 0x70, 0x49, 0x1C, 0x27, 0x78, 0xB9, 0x42, 0xF2, 0xDB, 0xF9, 0xB2, + 0x02, 0xEB, 0x41, 0x02, + 0x00, 0xEB, 0x41, 0x00, 0x5B, 0x1E, 0xE7, 0xD2, 0x5B, 0x48, 0x5C, 0x4F, + 0x02, 0x9B, 0x02, 0x68, + 0xD9, 0xF8, 0x00, 0x10, 0x38, 0x68, 0x00, 0xF0, 0x73, 0xFA, 0x28, 0x68, + 0x90, 0xF8, 0xC0, 0x02, + 0x80, 0x07, 0x06, 0xD5, 0x23, 0x78, 0x32, 0x78, 0x39, 0x68, 0x00, 0x98, + 0x00, 0xF0, 0x1C, 0xF8, + 0x06, 0xE0, 0xBB, 0xF9, 0x00, 0x00, 0x39, 0x68, 0x42, 0x00, 0x00, 0x98, + 0x0E, 0xF0, 0x55, 0xFE, + 0x28, 0x68, 0x90, 0xF8, 0xC0, 0x02, 0x00, 0x07, 0x08, 0xD5, 0x00, 0x99, + 0x23, 0x78, 0x32, 0x78, + 0x03, 0xB0, 0x08, 0x46, 0xBD, 0xE8, 0xF0, 0x4F, 0x00, 0xF0, 0x05, 0xBC, + 0xBD, 0xE8, 0xFE, 0x8F, + 0x47, 0x49, 0x00, 0x20, 0x08, 0x70, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x4F, + 0xA7, 0xB0, 0x1C, 0x46, + 0x0D, 0x46, 0x06, 0x46, 0x17, 0x46, 0xEA, 0x46, 0x0D, 0xF1, 0x4C, 0x0B, + 0x3C, 0xE0, 0x00, 0x22, + 0x60, 0x1E, 0x00, 0xF0, 0xFF, 0x09, 0x11, 0x46, 0x10, 0x46, 0x11, 0xE0, + 0x35, 0xF9, 0x10, 0x30, + 0x1A, 0x44, 0x43, 0x1C, 0x92, 0xFB, 0xF3, 0xFC, 0x2A, 0xF8, 0x10, 0xC0, + 0xA9, 0xEB, 0x00, 0x0C, + 0x40, 0x1C, 0x35, 0xF9, 0x1C, 0x80, 0x41, 0x44, 0x91, 0xFB, 0xF3, 0xF3, + 0x2B, 0xF8, 0x1C, 0x30, + 0xA0, 0x42, 0xEB, 0xDB, 0x20, 0x46, 0x52, 0x46, 0x5B, 0x46, 0x0C, 0xE0, + 0x32, 0xF9, 0x10, 0x10, + 0x33, 0xF9, 0x10, 0xC0, 0x61, 0x44, 0x35, 0xF8, 0x10, 0xC0, 0x01, 0xEB, + 0xD1, 0x71, 0xAC, 0xEB, + 0x61, 0x01, 0x26, 0xF8, 0x10, 0x10, 0x40, 0x1E, 0xF0, 0xD2, 0x20, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0xC0, 0x02, 0x40, 0x07, 0x04, 0xD5, 0x31, 0x46, 0x22, 0x46, 0x08, 0x46, + 0x00, 0xF0, 0x08, 0xF8, + 0x05, 0xEB, 0x44, 0x05, 0x06, 0xEB, 0x44, 0x06, 0x7F, 0x1E, 0xC0, 0xD2, + 0x27, 0xB0, 0x35, 0xE7, + 0xF0, 0xB5, 0x16, 0x4B, 0x00, 0x26, 0x35, 0x46, 0xD3, 0xF8, 0x00, 0xE0, + 0x34, 0x46, 0x13, 0x46, + 0xBE, 0xF9, 0xC6, 0x72, 0xC7, 0xF1, 0x00, 0x0C, 0x06, 0xE0, 0x00, 0xBF, + 0x31, 0xF9, 0x13, 0x70, + 0x67, 0x45, 0x01, 0xDA, 0x3E, 0x44, 0x6D, 0x1C, 0x5B, 0x1E, 0xF7, 0xD2, + 0x00, 0x2D, 0x01, 0xDD, + 0x96, 0xFB, 0xF5, 0xF4, 0xBE, 0xF8, 0xC8, 0x32, 0x5E, 0x42, 0xA6, 0x42, + 0x00, 0xDD, 0x1C, 0x44, + 0x53, 0x1B, 0x63, 0x43, 0x93, 0xFB, 0xF2, 0xF3, 0x05, 0xE0, 0x00, 0xBF, + 0x31, 0xF8, 0x12, 0x40, + 0xE4, 0x1A, 0x20, 0xF8, 0x12, 0x40, 0x52, 0x1E, 0xF8, 0xD2, 0xF0, 0xBD, + 0x4C, 0x07, 0x10, 0x00, + 0x4A, 0x0C, 0x01, 0x20, 0x80, 0x05, 0x10, 0x00, 0xFE, 0x06, 0x10, 0x00, + 0x1C, 0x07, 0x10, 0x00, + 0xEE, 0x06, 0x10, 0x00, 0xED, 0x06, 0x10, 0x00, 0x9C, 0x06, 0x10, 0x00, + 0x18, 0x07, 0x10, 0x00, + 0xF3, 0x06, 0x10, 0x00, 0x2D, 0xE9, 0xFF, 0x4F, 0x83, 0xB0, 0x9A, 0x46, + 0x17, 0x46, 0x89, 0x46, + 0x00, 0x25, 0x4F, 0xF0, 0xAA, 0x0B, 0xDD, 0xF8, 0x40, 0x80, 0x5B, 0xE0, + 0x11, 0x98, 0x05, 0xFB, + 0x00, 0xF6, 0x05, 0xEB, 0x85, 0x00, 0xC4, 0x00, 0x1A, 0xF8, 0x04, 0x00, + 0x08, 0xB9, 0x38, 0x5D, + 0xE8, 0xB3, 0x0A, 0xF8, 0x04, 0xB0, 0x39, 0xF9, 0x16, 0x00, 0x00, 0xF0, + 0xC9, 0xF8, 0x29, 0xF8, + 0x16, 0x00, 0x38, 0x5D, 0x98, 0xB3, 0x39, 0x19, 0x01, 0x91, 0x11, 0xF8, + 0x28, 0x1C, 0x81, 0x42, + 0x1E, 0xD0, 0xAA, 0x28, 0x1C, 0xD0, 0x01, 0x98, 0x00, 0xF8, 0x28, 0xBC, + 0x11, 0x98, 0x31, 0x1A, + 0x03, 0x98, 0x00, 0x91, 0x30, 0xF9, 0x11, 0x00, 0x00, 0xF0, 0xB2, 0xF8, + 0x03, 0x9A, 0x00, 0x99, + 0x22, 0xF8, 0x11, 0x00, 0x0A, 0xEB, 0x04, 0x01, 0x01, 0xF8, 0x28, 0xBC, + 0x00, 0x99, 0x39, 0xF9, + 0x11, 0x00, 0x00, 0xF0, 0xA5, 0xF8, 0x00, 0x99, 0x29, 0xF8, 0x11, 0x00, + 0x38, 0x5D, 0x70, 0xB1, + 0x01, 0x98, 0x90, 0xF8, 0x28, 0x10, 0x38, 0x5D, 0x81, 0x42, 0x1A, 0xD0, + 0xAA, 0x28, 0x18, 0xD0, + 0x01, 0x98, 0x80, 0xF8, 0x28, 0xB0, 0x11, 0x98, 0x06, 0x44, 0x03, 0x98, + 0x00, 0xE0, 0x10, 0xE0, + 0x30, 0xF9, 0x16, 0x00, 0x00, 0xF0, 0x8C, 0xF8, 0x03, 0x99, 0x21, 0xF8, + 0x16, 0x00, 0x0A, 0xEB, + 0x04, 0x01, 0x81, 0xF8, 0x28, 0xB0, 0x39, 0xF9, 0x16, 0x00, 0x00, 0xF0, + 0x81, 0xF8, 0x29, 0xF8, + 0x16, 0x00, 0x6D, 0x1C, 0x45, 0x45, 0xA1, 0xD3, 0x07, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x44, 0x49, + 0x00, 0x20, 0x08, 0x60, 0x70, 0x47, 0x42, 0x49, 0x08, 0x60, 0x70, 0x47, + 0x2D, 0xE9, 0xF0, 0x4F, + 0x05, 0x46, 0x40, 0x48, 0x8B, 0xB0, 0x17, 0x46, 0x00, 0x78, 0x8A, 0x46, + 0x00, 0x28, 0x65, 0xD0, + 0x3D, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x00, 0x04, 0x80, 0x07, 0x5F, 0xD5, + 0x3B, 0x48, 0x04, 0x90, + 0x3B, 0x48, 0xDF, 0xF8, 0xDC, 0xB0, 0x01, 0x24, 0x90, 0xF8, 0x00, 0x80, + 0xDB, 0xF8, 0x00, 0x90, + 0x22, 0xE0, 0x01, 0x20, 0xA0, 0x40, 0x10, 0xEA, 0x09, 0x0F, 0x1C, 0xD1, + 0x35, 0x48, 0x00, 0xEB, + 0x84, 0x06, 0x04, 0x98, 0xB1, 0x78, 0x0E, 0xF0, 0xA9, 0xFE, 0x01, 0x46, + 0xB2, 0x78, 0x00, 0x23, + 0x0E, 0xE0, 0x30, 0x78, 0x06, 0xE0, 0x00, 0xBF, 0x11, 0xF8, 0x00, 0xC0, + 0xA4, 0x45, 0x00, 0xD1, + 0x0B, 0x54, 0x40, 0x1C, 0x96, 0xF8, 0x01, 0xC0, 0x84, 0x45, 0xF5, 0xDA, + 0x28, 0x31, 0x52, 0x1C, + 0xF0, 0x78, 0x90, 0x42, 0xED, 0xDA, 0x64, 0x1C, 0x44, 0x45, 0xDA, 0xD9, + 0xA8, 0x46, 0x05, 0xF1, + 0x02, 0x09, 0x00, 0x21, 0x21, 0x48, 0x0E, 0xF0, 0x89, 0xFE, 0x20, 0x4E, + 0x07, 0x90, 0x00, 0x21, + 0x70, 0x1C, 0x0E, 0xF0, 0x83, 0xFE, 0x05, 0xEB, 0x47, 0x04, 0xA5, 0x1E, + 0x3E, 0x44, 0x06, 0x90, + 0x70, 0x1E, 0x00, 0x21, 0x24, 0x1F, 0x0E, 0xF0, 0x79, 0xFE, 0x03, 0x90, + 0xB0, 0x1E, 0x00, 0x21, + 0x0E, 0xF0, 0x74, 0xFE, 0xCD, 0xE9, 0x00, 0xA7, 0xDD, 0xE9, 0x06, 0x32, + 0x06, 0x46, 0x49, 0x46, + 0x40, 0x46, 0xFF, 0xF7, 0x27, 0xFF, 0xCD, 0xE9, 0x00, 0xA7, 0x33, 0x46, + 0x21, 0x46, 0x28, 0x46, + 0x03, 0x9A, 0xFF, 0xF7, 0x1F, 0xFF, 0x00, 0x20, 0xCB, 0xF8, 0x00, 0x00, + 0x0B, 0xB0, 0x84, 0xE7, + 0x09, 0x49, 0x09, 0x68, 0x91, 0xF8, 0x08, 0x24, 0x42, 0x43, 0x64, 0x20, + 0x92, 0xFB, 0xF0, 0xF0, + 0xB1, 0xF8, 0x06, 0x24, 0x00, 0xB2, 0x82, 0x42, 0x01, 0xDA, 0xB1, 0xF9, + 0x06, 0x04, 0x70, 0x47, + 0x7C, 0x05, 0x10, 0x00, 0xA4, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0xC2, 0x18, 0x01, 0x20, + 0x39, 0x06, 0x10, 0x00, 0x5A, 0x1C, 0x01, 0x20, 0x2D, 0xE9, 0xF0, 0x4F, + 0xFE, 0x4C, 0x80, 0x25, + 0xFE, 0x4E, 0x23, 0x68, 0x93, 0xF8, 0x31, 0x10, 0x93, 0xF8, 0x30, 0x00, + 0x01, 0xFB, 0x00, 0xF2, + 0x02, 0xE0, 0x00, 0xBF, 0x26, 0xF8, 0x12, 0x50, 0x52, 0x1E, 0xFB, 0xD2, + 0x93, 0xF8, 0xA0, 0x22, + 0xA6, 0x46, 0x12, 0x07, 0x4F, 0xF0, 0x64, 0x08, 0x31, 0xD5, 0x4A, 0x1E, + 0x02, 0xFB, 0x00, 0xFA, + 0xDF, 0xF8, 0xC8, 0xB3, 0x03, 0xF5, 0x94, 0x69, 0x02, 0x46, 0x26, 0xE0, + 0x19, 0xF8, 0x02, 0x30, + 0x0A, 0xEB, 0x02, 0x04, 0xDB, 0x01, 0xB3, 0xFB, 0xF8, 0xF3, 0x0B, 0xEB, + 0x44, 0x05, 0x0C, 0x46, + 0x19, 0xE0, 0x80, 0x2B, 0x05, 0xDD, 0xC3, 0xF1, 0x80, 0x06, 0x66, 0x43, + 0x96, 0xFB, 0xF1, 0xF6, + 0x06, 0xE0, 0xA3, 0xF1, 0x80, 0x06, 0x06, 0xFB, 0x04, 0xF7, 0x97, 0xFB, + 0xF1, 0xF7, 0xF6, 0x1B, + 0xB5, 0xF9, 0x00, 0x70, 0x80, 0x36, 0x77, 0x43, 0xFE, 0x17, 0x07, 0xEB, + 0x56, 0x66, 0xF6, 0x11, + 0x2E, 0x80, 0xA5, 0xEB, 0x40, 0x05, 0x64, 0x1E, 0xE3, 0xD2, 0x52, 0x1E, + 0xD6, 0xD2, 0xDE, 0xF8, + 0x00, 0x20, 0xF2, 0x46, 0x92, 0xF8, 0xA0, 0x32, 0xDB, 0x06, 0x2F, 0xD5, + 0x02, 0xF5, 0x98, 0x69, + 0xD6, 0x4B, 0x4A, 0x1E, 0x42, 0x43, 0x03, 0xEB, 0x42, 0x05, 0x0A, 0x46, + 0x24, 0xE0, 0x00, 0xBF, + 0x19, 0xF8, 0x02, 0x30, 0xDB, 0x01, 0xB3, 0xFB, 0xF8, 0xF6, 0x03, 0x46, + 0x18, 0xE0, 0x80, 0x2E, + 0x05, 0xDD, 0xC6, 0xF1, 0x80, 0x04, 0x5C, 0x43, 0x94, 0xFB, 0xF0, 0xF4, + 0x06, 0xE0, 0xA6, 0xF1, + 0x80, 0x04, 0x04, 0xFB, 0x03, 0xF7, 0x97, 0xFB, 0xF0, 0xF7, 0xE4, 0x1B, + 0x35, 0xF9, 0x13, 0x70, + 0x80, 0x34, 0x67, 0x43, 0xFC, 0x17, 0x07, 0xEB, 0x54, 0x64, 0xE4, 0x11, + 0x25, 0xF8, 0x13, 0x40, + 0x5B, 0x1E, 0xE4, 0xD2, 0xA5, 0xEB, 0x40, 0x05, 0x52, 0x1E, 0xD9, 0xD2, + 0xDA, 0xF8, 0x00, 0x40, + 0x94, 0xF8, 0xA1, 0x22, 0xD2, 0x07, 0x20, 0xD0, 0xBC, 0x4E, 0x00, 0x23, + 0x04, 0xF5, 0x9C, 0x64, + 0x19, 0xE0, 0x00, 0xBF, 0x03, 0xFB, 0x00, 0xF2, 0x06, 0xEB, 0x42, 0x07, + 0x00, 0x22, 0x0F, 0xE0, + 0xA5, 0x5C, 0xED, 0x01, 0xB5, 0xFB, 0xF8, 0xFC, 0x37, 0xF9, 0x12, 0x50, + 0x05, 0xFB, 0x0C, 0xF5, + 0x4F, 0xEA, 0xE5, 0x7C, 0x05, 0xEB, 0x5C, 0x65, 0xED, 0x11, 0x27, 0xF8, + 0x12, 0x50, 0x52, 0x1C, + 0x82, 0x42, 0xED, 0xD3, 0x5B, 0x1C, 0x8B, 0x42, 0xE4, 0xD3, 0xBD, 0xE8, + 0xF0, 0x8F, 0x30, 0xB5, + 0x0B, 0xE0, 0x00, 0xBF, 0x31, 0xF9, 0x13, 0x40, 0x32, 0xF9, 0x13, 0x50, + 0x6C, 0x43, 0xE5, 0x17, + 0x04, 0xEB, 0x55, 0x64, 0xE4, 0x11, 0x20, 0xF8, 0x13, 0x40, 0x5B, 0x1E, + 0xF2, 0xD2, 0x30, 0xBD, + 0x08, 0xB5, 0x00, 0x93, 0x13, 0x46, 0xA2, 0x4A, 0xB2, 0xF9, 0x00, 0x20, + 0x0B, 0xF0, 0x06, 0xFC, + 0x08, 0xBD, 0x2D, 0xE9, 0xF0, 0x5F, 0xDF, 0xF8, 0x70, 0x92, 0xDF, 0xF8, + 0x78, 0xB2, 0xD9, 0xF8, + 0x00, 0x10, 0xDB, 0xF8, 0x00, 0xC0, 0xB1, 0xF9, 0x00, 0x23, 0xB1, 0xF9, + 0x22, 0x33, 0xB1, 0xF9, + 0x42, 0x63, 0x5F, 0xEA, 0x8C, 0x70, 0x07, 0xD5, 0x97, 0x48, 0x00, 0x78, + 0x01, 0x28, 0x03, 0xD1, + 0xB1, 0xF9, 0x4E, 0x33, 0xB1, 0xF9, 0x50, 0x23, 0x94, 0x48, 0x47, 0x78, + 0x01, 0x2F, 0x7C, 0xD0, + 0x02, 0x2F, 0x04, 0xD3, 0xB1, 0xF8, 0x04, 0x03, 0x08, 0xB1, 0xB1, 0xF9, + 0x04, 0x23, 0x90, 0x4D, + 0x28, 0x78, 0x98, 0xB1, 0x91, 0xF8, 0x69, 0x03, 0x64, 0x24, 0x00, 0xFB, + 0x02, 0xF8, 0x98, 0xFB, + 0xF4, 0xF8, 0x42, 0x44, 0x00, 0xFB, 0x03, 0xF8, 0x70, 0x43, 0x98, 0xFB, + 0xF4, 0xF8, 0x90, 0xFB, + 0xF4, 0xF0, 0x43, 0x44, 0x30, 0x44, 0x12, 0xB2, 0x1B, 0xB2, 0x06, 0xB2, + 0x85, 0x4C, 0xDF, 0xF8, + 0x18, 0xA2, 0xDF, 0xF8, 0x18, 0xE2, 0x22, 0x80, 0xAA, 0xF8, 0x00, 0x30, + 0xAE, 0xF8, 0x00, 0x60, + 0x91, 0xF8, 0x02, 0x03, 0xDF, 0xF8, 0x08, 0x92, 0x10, 0x1A, 0x00, 0xB2, + 0xA9, 0xF8, 0x00, 0x00, + 0x91, 0xF8, 0x24, 0x83, 0xA3, 0xEB, 0x08, 0x08, 0x7E, 0x4B, 0xA3, 0xF8, + 0x00, 0x80, 0x91, 0xF8, + 0x44, 0x13, 0x76, 0x1A, 0x7C, 0x49, 0x5F, 0xEA, 0xCC, 0x78, 0x0E, 0x80, + 0x01, 0xD0, 0x02, 0x2F, + 0x02, 0xD3, 0xAA, 0xF8, 0x00, 0x20, 0x18, 0x80, 0xDA, 0x46, 0x5F, 0xEA, + 0x8C, 0x76, 0x01, 0xD5, + 0x02, 0x2F, 0x02, 0xD3, 0xAE, 0xF8, 0x00, 0x20, 0x08, 0x80, 0xB1, 0xF9, + 0x00, 0x20, 0xB3, 0xF9, + 0x00, 0x10, 0xC8, 0x46, 0x4F, 0x46, 0x0A, 0xF0, 0xF1, 0xFB, 0x70, 0x4E, + 0x00, 0xB2, 0x70, 0x4A, + 0x30, 0x80, 0x21, 0x88, 0x6F, 0x4B, 0x11, 0x80, 0xDF, 0xF8, 0x7C, 0x91, + 0x39, 0x88, 0x19, 0x80, + 0xD9, 0xF8, 0x00, 0x10, 0x91, 0xF8, 0x00, 0x74, 0xFF, 0x07, 0x10, 0xD0, + 0x5F, 0x4F, 0x7F, 0x78, + 0x0F, 0xB1, 0x91, 0xF8, 0x05, 0x74, 0xB1, 0xF8, 0x02, 0xC4, 0x67, 0x44, + 0x17, 0x80, 0x91, 0xF8, + 0x04, 0x14, 0x79, 0x1A, 0x09, 0xB2, 0x19, 0x80, 0x0A, 0xF0, 0xDE, 0xFB, + 0x30, 0x80, 0x62, 0x4F, + 0x62, 0x4A, 0x20, 0x88, 0x38, 0x80, 0x10, 0x80, 0x00, 0xE0, 0x0C, 0xE0, + 0x60, 0x49, 0xB8, 0xF8, + 0x00, 0x00, 0x08, 0x80, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x40, 0x34, + 0xDB, 0x07, 0x26, 0xD0, + 0x2B, 0x78, 0x6B, 0xB1, 0x23, 0xE0, 0x91, 0xF8, 0x03, 0x03, 0x10, 0x44, + 0x02, 0xB2, 0x91, 0xF8, + 0x25, 0x03, 0x18, 0x44, 0x03, 0xB2, 0x91, 0xF8, 0x45, 0x03, 0x30, 0x44, + 0x06, 0xB2, 0x6E, 0xE7, + 0xB0, 0xF8, 0x42, 0x34, 0x13, 0xB1, 0xB0, 0xF8, 0x42, 0x34, 0x3B, 0x80, + 0xB0, 0xF8, 0x44, 0x34, + 0x33, 0xB1, 0xB0, 0xF8, 0x44, 0x34, 0x13, 0x80, 0x90, 0xF8, 0x46, 0x04, + 0x18, 0x1A, 0x08, 0x80, + 0xB1, 0xF9, 0x00, 0x10, 0xB6, 0xF9, 0x00, 0x00, 0x0A, 0xF0, 0xA6, 0xFB, + 0x30, 0x80, 0x49, 0x4E, + 0x20, 0x88, 0x30, 0x80, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x20, 0x14, + 0xC9, 0x07, 0x07, 0xD0, + 0x29, 0x78, 0x29, 0xB9, 0xB0, 0xF8, 0x21, 0x14, 0x11, 0xB1, 0xB0, 0xF8, + 0x21, 0x14, 0x31, 0x80, + 0x9A, 0xF8, 0x00, 0x10, 0xC9, 0x06, 0x07, 0xD5, 0x3F, 0x49, 0x09, 0x78, + 0x21, 0xB1, 0xB0, 0xF8, + 0x6B, 0x12, 0x21, 0x80, 0xA8, 0xF8, 0x00, 0x10, 0x3C, 0x4C, 0xB0, 0xF9, + 0xB2, 0x02, 0x20, 0x80, + 0xB7, 0xF9, 0x00, 0x10, 0x0A, 0xF0, 0x80, 0xFB, 0x00, 0xB2, 0x20, 0x80, + 0xB6, 0xF9, 0x00, 0x10, + 0x0A, 0xF0, 0x7A, 0xFB, 0x20, 0x80, 0xBD, 0xE8, 0xF0, 0x9F, 0x2D, 0xE9, + 0xFF, 0x4F, 0x8A, 0x46, + 0x81, 0x46, 0x33, 0x49, 0x0D, 0x98, 0x93, 0x46, 0x4A, 0x0C, 0x04, 0x46, + 0x08, 0xE0, 0x00, 0xBF, + 0x3A, 0xF9, 0x14, 0x30, 0x93, 0x42, 0x00, 0xDA, 0x1A, 0x46, 0x8B, 0x42, + 0x00, 0xDD, 0x19, 0x46, + 0x64, 0x1E, 0xF5, 0xD2, 0x00, 0x25, 0x00, 0x29, 0x01, 0xDA, 0x0D, 0x46, + 0x02, 0xE0, 0x00, 0x2A, + 0x00, 0xDD, 0x15, 0x46, 0x00, 0x23, 0x1C, 0x46, 0x1E, 0x46, 0x19, 0x46, + 0x1F, 0x46, 0x02, 0x46, + 0x12, 0xE0, 0x00, 0xBF, 0x3A, 0xF9, 0x12, 0xC0, 0xAC, 0xEB, 0x05, 0x0C, + 0xDC, 0x45, 0x0B, 0xDA, + 0x0C, 0xEB, 0x0B, 0x08, 0xB8, 0xF1, 0x00, 0x0F, 0x06, 0xDD, 0x02, 0xFB, + 0x02, 0x44, 0x02, 0xFB, + 0x0C, 0x11, 0x13, 0x44, 0x66, 0x44, 0x7F, 0x1C, 0x52, 0x1E, 0xEB, 0xD2, + 0x04, 0xFB, 0x07, 0xF2, + 0x03, 0xFB, 0x13, 0x2E, 0x2E, 0xE0, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x86, 0x12, 0x01, 0x20, + 0xFE, 0x06, 0x10, 0x00, 0x04, 0x07, 0x10, 0x00, 0xF9, 0x06, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, + 0xFD, 0x06, 0x10, 0x00, 0x8C, 0x06, 0x10, 0x00, 0x8E, 0x06, 0x10, 0x00, + 0x90, 0x06, 0x10, 0x00, + 0x92, 0x06, 0x10, 0x00, 0x94, 0x06, 0x10, 0x00, 0x96, 0x06, 0x10, 0x00, + 0x98, 0x06, 0x10, 0x00, + 0xA0, 0x06, 0x10, 0x00, 0xA2, 0x06, 0x10, 0x00, 0xA8, 0x06, 0x10, 0x00, + 0xAA, 0x06, 0x10, 0x00, + 0xAC, 0x06, 0x10, 0x00, 0xA6, 0x06, 0x10, 0x00, 0x74, 0x05, 0x10, 0x00, + 0x9A, 0x06, 0x10, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0x01, 0xFB, 0x07, 0xF2, 0x03, 0xFB, 0x16, 0x27, + 0x74, 0x43, 0x01, 0xFB, + 0x13, 0x46, 0x00, 0x24, 0x21, 0x46, 0x02, 0x46, 0x25, 0xE0, 0x00, 0x23, + 0xBE, 0xF1, 0x00, 0x0F, + 0x0F, 0xD0, 0x07, 0xFB, 0x02, 0x6C, 0x9C, 0xFB, 0xFE, 0xF3, 0xDC, 0x46, + 0x5B, 0x45, 0x01, 0xDD, + 0x63, 0x46, 0x06, 0xE0, 0xDD, 0xF8, 0x0C, 0xC0, 0x13, 0xEB, 0x0C, 0x0F, + 0x01, 0xD5, 0x03, 0x9B, + 0x5B, 0x42, 0x3A, 0xF8, 0x12, 0xC0, 0x2B, 0x44, 0xAC, 0xEB, 0x03, 0x03, + 0xDD, 0xF8, 0x0C, 0xC0, + 0x1B, 0xB2, 0x63, 0x45, 0x05, 0xDA, 0x9C, 0x44, 0xBC, 0xF1, 0x00, 0x0F, + 0x01, 0xDD, 0x1C, 0x44, + 0x49, 0x1C, 0x29, 0xF8, 0x12, 0x30, 0x52, 0x1E, 0xD7, 0xD2, 0x01, 0xB9, + 0x01, 0x21, 0x94, 0xFB, + 0xF1, 0xF1, 0x04, 0xE0, 0x39, 0xF8, 0x10, 0x20, 0x52, 0x1A, 0x29, 0xF8, + 0x10, 0x20, 0x40, 0x1E, + 0xF8, 0xD2, 0xBD, 0xE8, 0xFF, 0x8F, 0x2D, 0xE9, 0xF8, 0x43, 0x1F, 0x46, + 0xFE, 0x4B, 0x0E, 0x46, + 0x05, 0x46, 0x1B, 0x68, 0x14, 0x46, 0xB3, 0xF9, 0xCA, 0x92, 0xB3, 0xF9, + 0xCC, 0x82, 0x0A, 0xE0, + 0x43, 0x46, 0x4A, 0x46, 0x31, 0x46, 0x28, 0x46, 0x00, 0x97, 0xFF, 0xF7, + 0x3E, 0xFF, 0x06, 0xEB, + 0x47, 0x06, 0x05, 0xEB, 0x47, 0x05, 0x64, 0x1E, 0xF2, 0xD2, 0xBD, 0xE8, + 0xF8, 0x83, 0x08, 0xE0, + 0x30, 0xF9, 0x12, 0x30, 0x00, 0x2B, 0x00, 0xDA, 0x5B, 0x42, 0x8B, 0x42, + 0x01, 0xDD, 0x01, 0x20, + 0x70, 0x47, 0x52, 0x1E, 0xF4, 0xD2, 0x00, 0x20, 0x70, 0x47, 0x05, 0xE0, + 0x30, 0xF9, 0x12, 0x30, + 0x8B, 0x42, 0x01, 0xDD, 0x01, 0x20, 0x70, 0x47, 0x52, 0x1E, 0xF7, 0xD2, + 0x00, 0x20, 0x70, 0x47, + 0x2D, 0xE9, 0xFC, 0x47, 0x04, 0x46, 0xE5, 0x48, 0xE5, 0x4F, 0x13, 0x46, + 0x02, 0x68, 0x38, 0x68, + 0xFF, 0xF7, 0x0E, 0xFE, 0x03, 0x20, 0xF7, 0xF7, 0xEC, 0xFC, 0xDF, 0xF8, + 0x7C, 0x93, 0xDF, 0xF8, + 0x84, 0x83, 0xE1, 0x4D, 0xD9, 0xF8, 0x00, 0x00, 0xE0, 0x4E, 0x90, 0xF8, + 0xA0, 0x02, 0x80, 0x07, + 0x15, 0xD5, 0xDF, 0x48, 0xB0, 0xF9, 0x00, 0x20, 0xDE, 0x48, 0xB0, 0xF9, + 0x00, 0x10, 0xDE, 0x48, + 0xB0, 0xF9, 0x00, 0x00, 0x0A, 0xF0, 0x62, 0xFA, 0x03, 0xB2, 0x29, 0x78, + 0x30, 0x78, 0xCD, 0xE9, + 0x00, 0x01, 0x39, 0x68, 0xD8, 0xF8, 0x00, 0x20, 0x08, 0x46, 0x00, 0xF0, + 0x3F, 0xF9, 0xD7, 0x48, + 0xD8, 0xF8, 0x00, 0x20, 0x39, 0x68, 0xB0, 0xF9, 0x00, 0x30, 0x20, 0x46, + 0x0B, 0xF0, 0xE1, 0xF9, + 0x03, 0x20, 0xF7, 0xF7, 0xD9, 0xFC, 0xD9, 0xF8, 0x00, 0x00, 0x4F, 0x46, + 0x90, 0xF8, 0xA0, 0x02, + 0x00, 0x06, 0x05, 0xD5, 0x21, 0x46, 0x2B, 0x78, 0x32, 0x78, 0x08, 0x46, + 0xFF, 0xF7, 0x83, 0xFF, + 0x38, 0x68, 0x90, 0xF8, 0xA0, 0x02, 0x40, 0x07, 0x25, 0xD5, 0x30, 0x78, + 0x2E, 0x78, 0x32, 0x46, + 0x1F, 0xE0, 0x00, 0x21, 0x03, 0x46, 0x0C, 0xE0, 0x03, 0xFB, 0x06, 0x27, + 0x34, 0xF9, 0x17, 0x50, + 0x00, 0x2D, 0x04, 0xDD, 0x09, 0xB1, 0x8D, 0x42, 0x03, 0xDA, 0x29, 0x46, + 0x01, 0xE0, 0x00, 0x21, + 0x43, 0x1C, 0x5B, 0x1E, 0xF0, 0xD2, 0x00, 0x29, 0x0B, 0xDD, 0x03, 0x46, + 0x07, 0xE0, 0x00, 0xBF, + 0x03, 0xFB, 0x06, 0x25, 0x34, 0xF8, 0x15, 0x70, 0x7F, 0x1A, 0x24, 0xF8, + 0x15, 0x70, 0x5B, 0x1E, + 0xF6, 0xD2, 0x52, 0x1E, 0xDD, 0xD2, 0xBD, 0xE8, 0xFC, 0x87, 0x2D, 0xE9, + 0xF0, 0x5F, 0x92, 0x46, + 0xB3, 0x4A, 0x4F, 0xF0, 0x00, 0x08, 0x8B, 0x46, 0x15, 0x78, 0x06, 0x46, + 0x82, 0xF8, 0x00, 0x80, + 0xFF, 0xF7, 0x9F, 0xFD, 0x02, 0x21, 0xAF, 0x48, 0x07, 0xF0, 0x59, 0xFE, + 0xAE, 0x48, 0xAD, 0x4C, + 0x2A, 0x46, 0x00, 0x78, 0x31, 0x46, 0x01, 0x28, 0x20, 0x68, 0x5F, 0xD0, + 0xFF, 0xF7, 0x70, 0xFF, + 0x9D, 0x4D, 0xA1, 0x4F, 0xDF, 0xF8, 0x84, 0x92, 0x28, 0x68, 0x90, 0xF8, + 0xA1, 0x02, 0x80, 0x07, + 0x06, 0xD5, 0x21, 0x68, 0x3B, 0x78, 0x99, 0xF8, 0x00, 0x20, 0x08, 0x46, + 0x00, 0xF0, 0xDE, 0xF9, + 0x29, 0x68, 0x9E, 0x4E, 0x91, 0xF8, 0xA0, 0x02, 0x02, 0x07, 0x05, 0xD4, + 0xC0, 0x06, 0x03, 0xD4, + 0x91, 0xF8, 0xA1, 0x02, 0xC0, 0x07, 0x06, 0xD0, 0x21, 0x68, 0xB6, 0xF9, + 0x00, 0x30, 0x9B, 0x4A, + 0x08, 0x46, 0xFF, 0xF7, 0x54, 0xFD, 0xB6, 0xF9, 0x00, 0x00, 0x21, 0x68, + 0x42, 0x00, 0x98, 0x48, + 0x00, 0x68, 0x0E, 0xF0, 0x52, 0xF9, 0x3A, 0x78, 0x99, 0xF8, 0x00, 0x10, + 0x20, 0x68, 0xFF, 0xF7, + 0x0D, 0xFC, 0xDF, 0xF8, 0x50, 0x92, 0x99, 0xF8, 0x00, 0x00, 0x10, 0xF0, + 0x30, 0x0F, 0x04, 0xD0, + 0x51, 0x46, 0x58, 0x46, 0x22, 0x68, 0xFE, 0xF7, 0xCD, 0xFA, 0x8F, 0x48, + 0x8F, 0x4F, 0x40, 0x78, + 0x02, 0x28, 0x28, 0x68, 0x90, 0xF8, 0xA0, 0x12, 0x4F, 0xEA, 0x81, 0x61, + 0x19, 0xD3, 0x00, 0x29, + 0x07, 0xDA, 0x21, 0x68, 0xB0, 0xF9, 0xB0, 0x22, 0xB6, 0xF9, 0x00, 0x30, + 0x08, 0x46, 0x00, 0xF0, + 0x3E, 0xF9, 0x28, 0x68, 0x90, 0xF8, 0xA0, 0x12, 0x49, 0x06, 0x15, 0xD5, + 0xB0, 0xF9, 0xAE, 0x32, + 0x83, 0x4A, 0x21, 0x68, 0x38, 0x68, 0x06, 0xF0, 0xF9, 0xFA, 0x14, 0xE0, + 0xFF, 0xF7, 0x60, 0xFA, + 0x9E, 0xE7, 0x00, 0x29, 0x08, 0xDA, 0xB0, 0xF9, 0xB0, 0x22, 0xB6, 0xF9, + 0x00, 0x30, 0x21, 0x68, + 0x38, 0x68, 0x00, 0xF0, 0x24, 0xF9, 0x06, 0xE0, 0xB6, 0xF9, 0x00, 0x00, + 0x21, 0x68, 0x42, 0x00, + 0x38, 0x68, 0x0E, 0xF0, 0x0A, 0xF9, 0x02, 0x21, 0x6E, 0x48, 0x07, 0xF0, + 0x6B, 0xFE, 0x75, 0x48, + 0x00, 0x78, 0x60, 0xB1, 0xD9, 0xF8, 0x00, 0x00, 0x73, 0x49, 0xC2, 0x06, + 0x02, 0xD5, 0x0A, 0x78, + 0x01, 0x2A, 0x21, 0xD0, 0x80, 0x06, 0x02, 0xD5, 0x08, 0x78, 0x02, 0x28, + 0x1E, 0xD0, 0x6F, 0x48, + 0xB6, 0xF9, 0x00, 0x20, 0xB0, 0xF9, 0x00, 0x10, 0x38, 0x68, 0xFF, 0xF7, + 0xD6, 0xFE, 0x6C, 0x49, + 0x6C, 0x4D, 0xA8, 0xB1, 0x01, 0x20, 0x08, 0x70, 0x01, 0x46, 0x02, 0x24, + 0x6A, 0x48, 0x07, 0xF0, + 0xB6, 0xFD, 0x6B, 0x48, 0x69, 0x4B, 0xB0, 0xF9, 0x00, 0x20, 0x67, 0x48, + 0x01, 0x68, 0x38, 0x68, + 0x00, 0xF0, 0xFF, 0xF8, 0x28, 0x60, 0x0E, 0xE0, 0x03, 0x20, 0xE4, 0xE5, + 0x04, 0x20, 0xE2, 0xE5, + 0x64, 0x4A, 0xC5, 0xF8, 0x00, 0x80, 0x01, 0x24, 0xC2, 0xF8, 0x00, 0x80, + 0x5F, 0x4A, 0xC2, 0xF8, + 0x00, 0x80, 0x81, 0xF8, 0x00, 0x80, 0x20, 0x46, 0xD5, 0xE5, 0x4E, 0x49, + 0x10, 0xB5, 0x00, 0x20, + 0x08, 0x60, 0x57, 0x49, 0x08, 0x70, 0xFF, 0xF7, 0x7B, 0xFA, 0xFF, 0xF7, + 0x78, 0xFB, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0xF0, 0x01, 0xB8, 0x07, 0xE4, 0x3B, 0x48, 0x10, 0xB5, + 0x00, 0x68, 0x42, 0x49, + 0x40, 0x4B, 0xB0, 0xF8, 0x00, 0x23, 0x0A, 0x80, 0xB0, 0xF8, 0x22, 0x13, + 0x3C, 0x4C, 0x19, 0x80, + 0xB0, 0xF8, 0x42, 0x33, 0x23, 0x80, 0x50, 0x4C, 0x22, 0x80, 0x50, 0x4A, + 0x11, 0x80, 0x50, 0x49, + 0x0B, 0x80, 0x4B, 0x49, 0xB0, 0xF8, 0xB2, 0x02, 0x08, 0x80, 0x10, 0xBD, + 0x2D, 0xE9, 0xFF, 0x4F, + 0x9B, 0x46, 0xDD, 0xE9, 0x0D, 0x19, 0x86, 0x46, 0xA5, 0xE0, 0x00, 0xBF, + 0x01, 0x9A, 0x01, 0xFB, + 0x09, 0xF0, 0x02, 0xEB, 0x40, 0x04, 0x02, 0x9A, 0x46, 0x4F, 0x02, 0xEB, + 0x40, 0x06, 0x4F, 0xF0, + 0x01, 0x0C, 0x0E, 0xEB, 0x40, 0x05, 0x7B, 0x0C, 0xE2, 0x46, 0x4A, 0x46, + 0x15, 0xE0, 0x00, 0xBF, + 0x36, 0xF8, 0x12, 0x00, 0x34, 0xF8, 0x12, 0x80, 0xA0, 0xEB, 0x08, 0x00, + 0x00, 0xB2, 0x98, 0x42, + 0x00, 0xDA, 0x03, 0x46, 0xB8, 0x42, 0x00, 0xDD, 0x07, 0x46, 0x00, 0x28, + 0x02, 0xDD, 0x4F, 0xF0, + 0x00, 0x0A, 0x02, 0xE0, 0x01, 0xDA, 0x4F, 0xF0, 0x00, 0x0C, 0x52, 0x1E, + 0xE8, 0xD2, 0xBC, 0xF1, + 0x00, 0x0F, 0x04, 0xD0, 0xBA, 0xF1, 0x00, 0x0F, 0x01, 0xD0, 0x00, 0x20, + 0x0B, 0xE0, 0x5C, 0xEA, + 0x0A, 0x00, 0x08, 0xD0, 0xBC, 0xF1, 0x00, 0x0F, 0x04, 0xD1, 0xBA, 0xF1, + 0x00, 0x0F, 0x01, 0xD0, + 0x38, 0x46, 0x00, 0xE0, 0x18, 0x46, 0x00, 0x27, 0x3B, 0x46, 0x4A, 0x46, + 0xCB, 0xF1, 0x00, 0x0A, + 0x10, 0xE0, 0x00, 0xBF, 0x36, 0xF8, 0x12, 0xC0, 0x34, 0xF8, 0x12, 0x80, + 0xAC, 0xEB, 0x08, 0x0C, + 0xAC, 0xEB, 0x00, 0x0C, 0x0F, 0xFA, 0x8C, 0xFC, 0xDC, 0x45, 0x03, 0xDA, + 0xD4, 0x45, 0x01, 0xDD, + 0x67, 0x44, 0x5B, 0x1C, 0x52, 0x1E, 0x3F, 0xE0, 0x4C, 0x07, 0x10, 0x00, + 0x9C, 0x06, 0x10, 0x00, + 0x18, 0x07, 0x10, 0x00, 0x1C, 0x07, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, + 0x90, 0x06, 0x10, 0x00, 0x8E, 0x06, 0x10, 0x00, 0x8C, 0x06, 0x10, 0x00, + 0xFE, 0x06, 0x10, 0x00, + 0x79, 0x07, 0x10, 0x00, 0x80, 0x05, 0x10, 0x00, 0xF3, 0x06, 0x10, 0x00, + 0x86, 0x12, 0x01, 0x20, + 0x14, 0x07, 0x10, 0x00, 0x04, 0x07, 0x10, 0x00, 0x74, 0x07, 0x10, 0x00, + 0x10, 0x07, 0x10, 0x00, + 0x0E, 0x7A, 0x01, 0x00, 0x64, 0x05, 0x10, 0x00, 0x66, 0x05, 0x10, 0x00, + 0x98, 0x06, 0x10, 0x00, + 0xF5, 0x06, 0x10, 0x00, 0x7C, 0x06, 0x10, 0x00, 0x50, 0x06, 0x10, 0x00, + 0x84, 0x06, 0x10, 0x00, + 0x9A, 0x06, 0x10, 0x00, 0x80, 0x06, 0x10, 0x00, 0x92, 0x06, 0x10, 0x00, + 0x94, 0x06, 0x10, 0x00, + 0x96, 0x06, 0x10, 0x00, 0x00, 0x80, 0xFF, 0xFF, 0xAC, 0xD2, 0x03, 0xB9, + 0x01, 0x23, 0x97, 0xFB, + 0xF3, 0xF2, 0x02, 0x44, 0x48, 0x46, 0x04, 0xE0, 0x34, 0xF8, 0x10, 0x30, + 0x13, 0x44, 0x25, 0xF8, + 0x10, 0x30, 0x40, 0x1E, 0xF8, 0xD2, 0x49, 0x1E, 0xBF, 0xF4, 0x58, 0xAF, + 0xA9, 0xE5, 0x70, 0xB5, + 0x00, 0x24, 0x26, 0x46, 0x0A, 0xE0, 0x00, 0xBF, 0x31, 0xF9, 0x14, 0x50, + 0x95, 0x42, 0x02, 0xDA, + 0x20, 0xF8, 0x14, 0x60, 0x01, 0xE0, 0x20, 0xF8, 0x14, 0x50, 0x64, 0x1C, + 0x9C, 0x42, 0xF3, 0xDB, + 0x70, 0xBD, 0x2D, 0xE9, 0xFF, 0x5F, 0x45, 0x4C, 0x88, 0x46, 0x00, 0x26, + 0x07, 0x46, 0x92, 0x46, + 0x35, 0x46, 0x4F, 0xF4, 0x66, 0x71, 0x40, 0x46, 0x26, 0x60, 0x0E, 0xF0, + 0x4D, 0xF8, 0x00, 0x21, + 0x40, 0x46, 0x0E, 0xF0, 0x5B, 0xF9, 0x81, 0x46, 0x00, 0x21, 0x38, 0x46, + 0x0E, 0xF0, 0x4E, 0xF9, + 0x00, 0x22, 0x3B, 0x4B, 0x3B, 0x4F, 0x29, 0xE0, 0x00, 0x21, 0x4F, 0xF0, + 0x01, 0x0E, 0xDF, 0xF8, + 0xE8, 0xB0, 0x18, 0xE0, 0x30, 0xF9, 0x11, 0x80, 0xD0, 0x45, 0x05, 0xDD, + 0x09, 0xF8, 0x01, 0xE0, + 0x30, 0xF9, 0x11, 0xC0, 0x76, 0x1C, 0x65, 0x44, 0xDB, 0xF8, 0x00, 0xC0, + 0x30, 0xF9, 0x11, 0x80, + 0xBC, 0xF8, 0x55, 0xC3, 0xE0, 0x45, 0x05, 0xDD, 0xD4, 0xF8, 0x00, 0xC0, + 0x0C, 0xF1, 0x01, 0x0C, + 0xC4, 0xF8, 0x00, 0xC0, 0x49, 0x1C, 0x93, 0xF8, 0x00, 0xC0, 0x61, 0x45, + 0xE2, 0xDB, 0x0C, 0xF0, + 0xFF, 0x01, 0x09, 0xF1, 0x28, 0x09, 0x00, 0xEB, 0x41, 0x00, 0x52, 0x1C, + 0x39, 0x78, 0x8A, 0x42, + 0xD2, 0xDB, 0x03, 0x98, 0x05, 0x60, 0x30, 0x46, 0x04, 0xB0, 0x9C, 0xE4, + 0x2D, 0xE9, 0xF0, 0x43, + 0x91, 0x46, 0x1C, 0x46, 0x35, 0xE0, 0x21, 0x4D, 0x4F, 0xF0, 0x01, 0x0C, + 0x6A, 0x0C, 0xE0, 0x46, + 0x4F, 0x46, 0x11, 0xE0, 0x07, 0xFB, 0x03, 0x46, 0x31, 0xF9, 0x16, 0x60, + 0x96, 0x42, 0x00, 0xDA, + 0x32, 0x46, 0xAE, 0x42, 0x00, 0xDD, 0x35, 0x46, 0x00, 0x2E, 0x02, 0xDD, + 0x4F, 0xF0, 0x00, 0x08, + 0x02, 0xE0, 0x01, 0xDA, 0x4F, 0xF0, 0x00, 0x0C, 0x7F, 0x1E, 0xEB, 0xD2, + 0xBC, 0xF1, 0x00, 0x0F, + 0x02, 0xD0, 0xB8, 0xF1, 0x00, 0x0F, 0x14, 0xD1, 0x5C, 0xEA, 0x08, 0x06, + 0x11, 0xD0, 0xBC, 0xF1, + 0x00, 0x0F, 0x03, 0xD1, 0xB8, 0xF1, 0x00, 0x0F, 0x00, 0xD0, 0x2A, 0x46, + 0x4E, 0x46, 0x06, 0xE0, + 0x06, 0xFB, 0x03, 0x45, 0x31, 0xF8, 0x15, 0x70, 0xBF, 0x1A, 0x20, 0xF8, + 0x15, 0x70, 0x76, 0x1E, + 0xF6, 0xD2, 0x64, 0x1E, 0xC7, 0xD2, 0xBD, 0xE8, 0xF0, 0x83, 0x00, 0x00, + 0x80, 0x06, 0x10, 0x00, + 0xEE, 0x06, 0x10, 0x00, 0xED, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x00, 0x80, 0xFF, 0xFF, + 0x70, 0x47, 0xA5, 0x4A, 0x30, 0xB4, 0x12, 0x68, 0x92, 0xF8, 0xA4, 0x23, + 0x12, 0x09, 0x80, 0xF8, + 0x28, 0x20, 0x0A, 0x68, 0x02, 0x62, 0x4A, 0x68, 0x42, 0x62, 0xB1, 0xF9, + 0x02, 0x20, 0xD3, 0x17, + 0x1B, 0x04, 0x43, 0xEA, 0x12, 0x43, 0x12, 0x04, 0x82, 0x60, 0xC3, 0x60, + 0xB1, 0xF9, 0x00, 0x10, + 0xCA, 0x17, 0x12, 0x04, 0x42, 0xEA, 0x11, 0x42, 0x09, 0x04, 0x01, 0x60, + 0x42, 0x60, 0x10, 0x22, + 0x01, 0x46, 0x30, 0xBC, 0x10, 0x30, 0x0D, 0xF0, 0x20, 0xBF, 0x2D, 0xE9, + 0xF0, 0x4F, 0x92, 0x4F, + 0x81, 0x46, 0x8A, 0x46, 0x38, 0x68, 0x8F, 0xB0, 0x16, 0x46, 0xB0, 0xF8, + 0xA6, 0x13, 0x90, 0xF8, + 0xAA, 0x53, 0x01, 0xFB, 0x01, 0xFB, 0xB0, 0xF8, 0xA8, 0x13, 0x01, 0xFB, + 0x01, 0xF8, 0x0E, 0xF0, + 0x5B, 0xF8, 0x00, 0x28, 0x38, 0x68, 0x02, 0xD0, 0x90, 0xF8, 0xAC, 0x43, + 0x01, 0xE0, 0x90, 0xF8, + 0xAB, 0x43, 0xAC, 0x42, 0x00, 0xD2, 0x25, 0x46, 0x00, 0x2E, 0x02, 0xDB, + 0x89, 0xF8, 0x28, 0x60, + 0x19, 0xE0, 0x09, 0xF1, 0x24, 0x01, 0x99, 0xF8, 0x28, 0x60, 0x08, 0x1F, + 0x0A, 0xF0, 0x5B, 0xF8, + 0x58, 0x45, 0x01, 0xDB, 0x26, 0x46, 0x02, 0xE0, 0x40, 0x45, 0x00, 0xDC, + 0x2E, 0x46, 0x38, 0x68, + 0x99, 0xF8, 0x28, 0x10, 0x90, 0xF8, 0xA4, 0x03, 0x00, 0xF0, 0x0F, 0x02, + 0x30, 0x46, 0x0A, 0xF0, + 0x6D, 0xF8, 0x89, 0xF8, 0x28, 0x00, 0x99, 0xF8, 0x28, 0x10, 0x74, 0x48, + 0x00, 0xEB, 0x81, 0x00, + 0x01, 0x68, 0xCA, 0x17, 0xCD, 0xE9, 0x07, 0x21, 0x41, 0x6C, 0xCA, 0x17, + 0xCD, 0xE9, 0x04, 0x12, + 0xD0, 0xF8, 0xCC, 0x20, 0xD0, 0xF8, 0x88, 0x50, 0xD4, 0x17, 0x01, 0x94, + 0x93, 0x46, 0xDD, 0xE9, + 0x07, 0x21, 0xD9, 0xF8, 0x08, 0x30, 0xD9, 0xF8, 0x0C, 0x40, 0xA3, 0xFB, + 0x01, 0x07, 0x04, 0xFB, + 0x01, 0x71, 0x03, 0xFB, 0x02, 0x11, 0xEE, 0x17, 0x4F, 0xF4, 0x80, 0x32, + 0x00, 0x23, 0x0D, 0xF0, + 0x98, 0xFE, 0xBA, 0xF9, 0x02, 0x30, 0xB9, 0xF9, 0x26, 0x20, 0x01, 0x9C, + 0x9F, 0x18, 0xA7, 0xFB, + 0x0B, 0x38, 0x4F, 0xEA, 0xE7, 0x7C, 0x0C, 0xFB, 0x0B, 0x82, 0x07, 0xFB, + 0x04, 0x24, 0xB9, 0xF9, + 0x22, 0x20, 0xA2, 0xFB, 0x05, 0xC8, 0xD7, 0x17, 0x07, 0xFB, 0x05, 0x87, + 0x13, 0xEB, 0x0C, 0x03, + 0x02, 0xFB, 0x06, 0x72, 0x54, 0x41, 0x1F, 0x1A, 0x64, 0xEB, 0x01, 0x04, + 0xDD, 0xE9, 0x04, 0x12, + 0xD9, 0xF8, 0x18, 0x30, 0xD9, 0xF8, 0x1C, 0xC0, 0xA3, 0xFB, 0x01, 0x08, + 0x0C, 0xFB, 0x01, 0x81, + 0x03, 0xFB, 0x02, 0x11, 0x4F, 0xF4, 0x80, 0x32, 0x00, 0x23, 0x0D, 0xF0, + 0x6A, 0xFE, 0x38, 0x1A, + 0x64, 0xEB, 0x01, 0x04, 0xCD, 0xE9, 0x0D, 0x04, 0x06, 0x94, 0x0A, 0x90, + 0xDD, 0xE9, 0x07, 0x21, + 0xD9, 0xF8, 0x00, 0x30, 0xD9, 0xF8, 0x04, 0x40, 0xA3, 0xFB, 0x01, 0x07, + 0x04, 0xFB, 0x01, 0x71, + 0x03, 0xFB, 0x02, 0x11, 0x4F, 0xF4, 0x80, 0x32, 0x00, 0x23, 0x0D, 0xF0, + 0x52, 0xFE, 0xBA, 0xF9, + 0x00, 0x30, 0xB9, 0xF9, 0x24, 0x20, 0x01, 0x9C, 0x13, 0x44, 0xA3, 0xFB, + 0x0B, 0xC8, 0xDF, 0x17, + 0x07, 0xFB, 0x0B, 0x82, 0x03, 0xFB, 0x04, 0x27, 0xB9, 0xF9, 0x20, 0x20, + 0xA2, 0xFB, 0x05, 0x48, + 0xD3, 0x17, 0x03, 0xFB, 0x05, 0x83, 0x02, 0xFB, 0x06, 0x32, 0x1C, 0xEB, + 0x04, 0x03, 0x57, 0x41, + 0x1C, 0x1A, 0x67, 0xEB, 0x01, 0x07, 0xDD, 0xE9, 0x04, 0x12, 0xD9, 0xF8, + 0x10, 0x30, 0xD9, 0xF8, + 0x14, 0x50, 0xA3, 0xFB, 0x01, 0x06, 0x05, 0xFB, 0x01, 0x61, 0x03, 0xFB, + 0x02, 0x11, 0x4F, 0xF4, + 0x80, 0x32, 0x00, 0x23, 0x0D, 0xF0, 0x25, 0xFE, 0x25, 0x1A, 0x67, 0xEB, + 0x01, 0x07, 0xCD, 0xE9, + 0x0B, 0x57, 0xD9, 0xF8, 0x20, 0x10, 0xC9, 0xF8, 0x24, 0x10, 0xDA, 0xF8, + 0x00, 0x10, 0xC9, 0xF8, + 0x20, 0x10, 0x10, 0x22, 0x49, 0x46, 0x09, 0xF1, 0x10, 0x00, 0x0D, 0xF0, + 0x36, 0xFE, 0x10, 0x22, + 0x0B, 0xA9, 0x48, 0x46, 0x0D, 0xF0, 0x31, 0xFE, 0x0A, 0x98, 0x4F, 0xF4, + 0x00, 0x41, 0x06, 0x9C, + 0x40, 0x18, 0x44, 0xF1, 0x00, 0x01, 0x4F, 0xF4, 0x80, 0x32, 0x00, 0x23, + 0x0D, 0xF0, 0x01, 0xFE, + 0xAA, 0xF8, 0x02, 0x00, 0x4F, 0xF4, 0x00, 0x40, 0x28, 0x18, 0x47, 0xF1, + 0x00, 0x01, 0x4F, 0xF4, + 0x80, 0x32, 0x00, 0x23, 0x0D, 0xF0, 0xF5, 0xFD, 0xAA, 0xF8, 0x00, 0x00, + 0x0F, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x70, 0xB5, 0x0D, 0x46, 0x04, 0x46, 0x01, 0x46, 0x10, 0x22, + 0x10, 0x30, 0x0D, 0xF0, + 0x0C, 0xFE, 0xB5, 0xF9, 0x02, 0x00, 0xC1, 0x17, 0x09, 0x04, 0x41, 0xEA, + 0x10, 0x41, 0x00, 0x04, + 0xA0, 0x60, 0xE1, 0x60, 0xB5, 0xF9, 0x00, 0x00, 0xC1, 0x17, 0x09, 0x04, + 0x41, 0xEA, 0x10, 0x41, + 0x00, 0x04, 0x20, 0x60, 0x61, 0x60, 0x70, 0xBD, 0x4C, 0x07, 0x10, 0x00, + 0xFE, 0x78, 0x01, 0x00, + 0x70, 0xB5, 0x04, 0x46, 0x00, 0x20, 0x84, 0xF8, 0x42, 0x01, 0x94, 0xF8, + 0x3F, 0x01, 0xF8, 0x4D, + 0x0E, 0x46, 0x01, 0x28, 0x0B, 0xD0, 0x0D, 0xF0, 0x37, 0xFF, 0x00, 0x28, + 0x94, 0xF9, 0x4C, 0x01, + 0x35, 0xD0, 0xB0, 0x42, 0x28, 0x68, 0x90, 0xF8, 0x9B, 0x03, 0x1A, 0xD1, + 0x11, 0xE0, 0xF1, 0x48, + 0x00, 0x78, 0x58, 0xB1, 0x0D, 0xF0, 0x28, 0xFF, 0x00, 0x28, 0x94, 0xF9, + 0x4C, 0x01, 0x0B, 0xD0, + 0xB0, 0x42, 0x28, 0x68, 0x90, 0xF8, 0x4D, 0x03, 0x03, 0xD0, 0x0A, 0xE0, + 0x28, 0x68, 0x90, 0xF8, + 0x4B, 0x03, 0x00, 0xF0, 0x0F, 0x00, 0x05, 0xE0, 0xB0, 0x42, 0x28, 0x68, + 0x90, 0xF8, 0x4C, 0x03, + 0xF7, 0xD0, 0x00, 0x09, 0x84, 0xF8, 0x42, 0x01, 0xE3, 0x48, 0x00, 0x78, + 0x48, 0xB1, 0x29, 0x68, + 0x94, 0xF8, 0x42, 0x01, 0x91, 0xF8, 0x63, 0x12, 0x01, 0xF0, 0x0F, 0x01, + 0x08, 0x44, 0x84, 0xF8, + 0x42, 0x01, 0x20, 0x46, 0x00, 0xF0, 0x4A, 0xF9, 0x01, 0x28, 0x06, 0xD0, + 0x0F, 0xE0, 0xB0, 0x42, + 0x28, 0x68, 0x90, 0xF8, 0x9A, 0x03, 0xE4, 0xD1, 0xDB, 0xE7, 0x29, 0x68, + 0x94, 0xF8, 0x42, 0x01, + 0x91, 0xF8, 0x9C, 0x13, 0x01, 0xF0, 0x0F, 0x01, 0x08, 0x44, 0x84, 0xF8, + 0x42, 0x01, 0xD3, 0x48, + 0xD3, 0x49, 0x00, 0x78, 0x09, 0x78, 0x08, 0x43, 0x07, 0xD0, 0x29, 0x68, + 0x94, 0xF8, 0x42, 0x01, + 0x91, 0xF8, 0x9D, 0x13, 0x08, 0x44, 0x84, 0xF8, 0x42, 0x01, 0x70, 0xBD, + 0xC9, 0x49, 0x10, 0xB5, + 0x0C, 0x78, 0xC7, 0x49, 0x90, 0xF8, 0x42, 0x21, 0x09, 0x68, 0x91, 0xF8, + 0x9A, 0x33, 0x03, 0xF0, + 0x0F, 0x03, 0x5C, 0xB1, 0x91, 0xF8, 0x4C, 0x13, 0x01, 0xF0, 0x0F, 0x01, + 0xC9, 0x1A, 0x51, 0x1A, + 0x00, 0x29, 0x00, 0xDC, 0x00, 0x21, 0x80, 0xF8, 0x42, 0x11, 0x10, 0xBD, + 0x91, 0xF8, 0x4B, 0x13, + 0xF2, 0xE7, 0xC0, 0x49, 0x00, 0x20, 0x08, 0x70, 0xBF, 0x49, 0x08, 0x70, + 0xB9, 0x49, 0x08, 0x70, + 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x4F, 0x8B, 0xB0, 0x4F, 0xF0, 0x00, 0x09, + 0x00, 0xF5, 0x80, 0x55, + 0x04, 0x46, 0x8D, 0xF8, 0x10, 0x90, 0x8D, 0xF8, 0x14, 0x90, 0xB5, 0xF8, + 0xEC, 0x03, 0xB5, 0x4A, + 0x00, 0x04, 0x00, 0x0C, 0x0A, 0xD0, 0x4F, 0xF0, 0xFF, 0x36, 0x10, 0x78, + 0x31, 0x46, 0x4F, 0xF0, + 0x00, 0x48, 0x93, 0x46, 0x4F, 0xF0, 0x01, 0x0A, 0xF8, 0xB9, 0x04, 0xE0, + 0x48, 0x46, 0x82, 0xF8, + 0x00, 0x90, 0xAD, 0x49, 0xDE, 0xE0, 0x04, 0xF5, 0x80, 0x52, 0x00, 0x20, + 0x92, 0xF9, 0xF4, 0x73, + 0x22, 0xE0, 0x00, 0xBF, 0xD2, 0xF8, 0xEC, 0xC3, 0x0A, 0xFA, 0x00, 0xF3, + 0x1C, 0xEA, 0x03, 0x0F, + 0x18, 0xD0, 0x00, 0xEB, 0x00, 0x13, 0x03, 0xEB, 0x83, 0x03, 0x04, 0xEB, + 0x83, 0x03, 0x93, 0xF8, + 0x3E, 0xC1, 0xBC, 0xF1, 0x01, 0x0F, 0x01, 0xD0, 0x31, 0x46, 0x0F, 0xE0, + 0xB3, 0xF8, 0x44, 0xC0, + 0xBC, 0xF1, 0x00, 0x0F, 0x06, 0xD0, 0x5B, 0x6B, 0x93, 0xFB, 0xFC, 0xF3, + 0x98, 0x45, 0x01, 0xDA, + 0x98, 0x46, 0x01, 0x46, 0x40, 0x1C, 0x40, 0xB2, 0x87, 0x42, 0xDB, 0xDA, + 0x00, 0x27, 0xDF, 0xF8, + 0x40, 0x82, 0x01, 0x91, 0x9D, 0xE0, 0x00, 0xBF, 0xD5, 0xF8, 0xEC, 0x13, + 0x0A, 0xFA, 0x07, 0xF0, + 0x01, 0x42, 0x60, 0xD0, 0x07, 0xEB, 0x07, 0x10, 0x00, 0xEB, 0x80, 0x00, + 0x04, 0xEB, 0x80, 0x06, + 0x96, 0xF8, 0x3E, 0x01, 0x01, 0x28, 0x02, 0xD0, 0x05, 0x28, 0x08, 0xD0, + 0x10, 0xE0, 0x30, 0x46, + 0x01, 0x99, 0xFF, 0xF7, 0x0D, 0xFF, 0x02, 0x20, 0x86, 0xF8, 0x3E, 0x01, + 0x11, 0xE0, 0x30, 0x46, + 0x00, 0xF0, 0xB0, 0xF8, 0x06, 0x20, 0x86, 0xF8, 0x3E, 0x01, 0x30, 0x46, + 0x00, 0xF0, 0x48, 0xF9, + 0x96, 0xF8, 0x3E, 0x01, 0x02, 0x28, 0x04, 0xD0, 0x06, 0x28, 0x32, 0xD0, + 0x07, 0x28, 0x3B, 0xD0, + 0x46, 0xE0, 0x96, 0xF8, 0x42, 0x00, 0xC0, 0x07, 0x13, 0xD0, 0x30, 0x46, + 0x00, 0xF0, 0x7E, 0xF8, + 0x78, 0xB9, 0xD8, 0xF8, 0x00, 0x10, 0x96, 0xF8, 0x42, 0x01, 0x91, 0xF8, + 0x9C, 0x13, 0x01, 0xF0, + 0x0F, 0x01, 0x88, 0x42, 0x03, 0xD9, 0x40, 0x1A, 0x86, 0xF8, 0x42, 0x01, + 0x01, 0xE0, 0x86, 0xF8, + 0x42, 0x91, 0x6E, 0x48, 0x00, 0x78, 0x40, 0xB1, 0x96, 0xF8, 0x42, 0x01, + 0x10, 0xBB, 0xD8, 0xF8, + 0x00, 0x00, 0x90, 0xF8, 0x9D, 0x03, 0x86, 0xF8, 0x42, 0x01, 0x96, 0xF8, + 0x42, 0x01, 0xC8, 0xB9, + 0x03, 0x20, 0x86, 0xF8, 0x3E, 0x01, 0x9B, 0xF8, 0x00, 0x00, 0x40, 0x1C, + 0x8B, 0xF8, 0x00, 0x00, + 0x2B, 0xE0, 0x96, 0xF8, 0x43, 0x01, 0x18, 0xBB, 0x96, 0xF8, 0x42, 0x00, + 0x80, 0x07, 0x03, 0xD5, + 0x07, 0x20, 0x86, 0xF8, 0x3E, 0x01, 0x32, 0xE0, 0x08, 0x20, 0x86, 0xF8, + 0x3E, 0x01, 0x30, 0x46, + 0x00, 0xF0, 0xA7, 0xF8, 0x96, 0xF8, 0x3E, 0x01, 0x02, 0x28, 0x07, 0xD0, + 0x06, 0x28, 0x0C, 0xD0, + 0xC0, 0xB2, 0x03, 0x28, 0x11, 0xD0, 0x04, 0x28, 0x0F, 0xD0, 0x20, 0xE0, + 0x96, 0xF8, 0x42, 0x01, + 0xE8, 0xB1, 0x40, 0x1E, 0x86, 0xF8, 0x42, 0x01, 0x19, 0xE0, 0x96, 0xF8, + 0x43, 0x01, 0xB0, 0xB1, + 0xC0, 0xB2, 0x40, 0x1E, 0x86, 0xF8, 0x43, 0x01, 0x11, 0xE0, 0x96, 0xF8, + 0x3F, 0x01, 0x01, 0x28, + 0x02, 0xD0, 0x03, 0x28, 0x06, 0xD0, 0x0A, 0xE0, 0x9D, 0xF8, 0x14, 0x00, + 0x40, 0x1C, 0x8D, 0xF8, + 0x14, 0x00, 0x04, 0xE0, 0x9D, 0xF8, 0x10, 0x00, 0x40, 0x1C, 0x8D, 0xF8, + 0x10, 0x00, 0x7F, 0x1C, + 0x7F, 0xB2, 0x95, 0xF9, 0xF4, 0x03, 0xB8, 0x42, 0xBF, 0xF6, 0x5E, 0xAF, + 0x05, 0xAA, 0x04, 0xA9, + 0x20, 0x46, 0x00, 0xF0, 0x87, 0xF8, 0x41, 0x49, 0x9D, 0xF8, 0x10, 0x00, + 0x08, 0x70, 0x9D, 0xF8, + 0x14, 0x00, 0x3F, 0x49, 0x08, 0x70, 0x0B, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x90, 0xF8, 0x5B, 0x10, + 0x90, 0xF8, 0x5A, 0x20, 0x8A, 0x1A, 0xB0, 0xF8, 0x42, 0x10, 0x52, 0x1C, + 0x02, 0x2A, 0x0B, 0xD9, + 0x90, 0xF8, 0x5D, 0x20, 0x90, 0xF8, 0x5C, 0x30, 0x9A, 0x42, 0x05, 0xD1, + 0x41, 0xF0, 0x01, 0x01, + 0xA0, 0xF8, 0x42, 0x10, 0x01, 0x20, 0x70, 0x47, 0x21, 0xF0, 0x01, 0x01, + 0xA0, 0xF8, 0x42, 0x10, + 0x00, 0x20, 0x70, 0x47, 0x70, 0xB5, 0x00, 0x25, 0x04, 0x46, 0x80, 0xF8, + 0x43, 0x51, 0x0D, 0xF0, + 0x93, 0xFD, 0x01, 0x00, 0x22, 0x48, 0x0C, 0xD0, 0x01, 0x68, 0x01, 0x25, + 0x91, 0xF8, 0x9E, 0x13, + 0x5F, 0xEA, 0x11, 0x11, 0x84, 0xF8, 0x43, 0x11, 0x94, 0xF8, 0x3F, 0x11, + 0x01, 0x29, 0x06, 0xD0, + 0x0E, 0xE0, 0x01, 0x68, 0x91, 0xF8, 0x9E, 0x13, 0x01, 0xF0, 0x0F, 0x01, + 0xF2, 0xE7, 0x02, 0x68, + 0x94, 0xF8, 0x43, 0x11, 0x92, 0xF8, 0x4B, 0x23, 0x01, 0xEB, 0x12, 0x11, + 0x84, 0xF8, 0x43, 0x11, + 0x1D, 0xB9, 0x94, 0xF8, 0x42, 0x10, 0x89, 0x07, 0x0D, 0xD4, 0x01, 0x68, + 0xE2, 0x6A, 0x91, 0xF8, + 0x9F, 0x13, 0x01, 0xF0, 0x0F, 0x03, 0x9A, 0x42, 0x05, 0xD9, 0x94, 0xF8, + 0x43, 0x21, 0x02, 0xEB, + 0x11, 0x11, 0x84, 0xF8, 0x43, 0x11, 0x0C, 0x49, 0x09, 0x78, 0x00, 0x29, + 0x08, 0xD0, 0x00, 0x68, + 0x94, 0xF8, 0x43, 0x11, 0x90, 0xF8, 0x63, 0x02, 0x01, 0xEB, 0x10, 0x10, + 0x84, 0xF8, 0x43, 0x01, + 0x70, 0xBD, 0x08, 0x49, 0x08, 0x78, 0x00, 0x28, 0x01, 0xD0, 0x40, 0x1E, + 0x08, 0x70, 0x70, 0x47, + 0x4C, 0x07, 0x10, 0x00, 0xF9, 0x06, 0x10, 0x00, 0x74, 0x05, 0x10, 0x00, + 0x76, 0x06, 0x10, 0x00, + 0x7D, 0x07, 0x10, 0x00, 0xFA, 0x06, 0x10, 0x00, 0x20, 0x07, 0x10, 0x00, + 0xFB, 0x06, 0x10, 0x00, + 0xFC, 0x06, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x47, 0x16, 0x46, 0x07, 0x46, + 0x0B, 0x78, 0x34, 0x4A, + 0x01, 0x20, 0x23, 0xB9, 0x33, 0x78, 0x13, 0xB1, 0x10, 0x70, 0xBD, 0xE8, + 0xF0, 0x87, 0x00, 0x23, + 0x13, 0x70, 0x00, 0x29, 0xF9, 0xD0, 0x31, 0x78, 0x00, 0x29, 0xF6, 0xD0, + 0x00, 0x24, 0x07, 0xF5, + 0x80, 0x55, 0x80, 0x46, 0x4F, 0xF0, 0x02, 0x09, 0x1D, 0xE0, 0x00, 0xBF, + 0xD5, 0xF8, 0xEC, 0x13, + 0x08, 0xFA, 0x04, 0xF0, 0x01, 0x42, 0x14, 0xD0, 0x04, 0xEB, 0x04, 0x10, + 0x00, 0xEB, 0x80, 0x00, + 0x07, 0xEB, 0x80, 0x00, 0x90, 0xF8, 0x3E, 0x11, 0x03, 0x29, 0x0A, 0xD1, + 0x90, 0xF8, 0x3F, 0x11, + 0x01, 0x29, 0x06, 0xD1, 0x80, 0xF8, 0x3E, 0x91, 0xFF, 0xF7, 0xB3, 0xFF, + 0x30, 0x78, 0x40, 0x1E, + 0x30, 0x70, 0x64, 0x1C, 0x64, 0xB2, 0x95, 0xF9, 0xF4, 0x03, 0xA0, 0x42, + 0xDE, 0xDA, 0xCC, 0xE7, + 0x2D, 0xE9, 0xF0, 0x41, 0x17, 0x4D, 0x04, 0x46, 0x28, 0x68, 0x90, 0xF8, + 0x81, 0x03, 0xC0, 0x07, + 0x24, 0xD0, 0x21, 0x46, 0x20, 0x1D, 0x09, 0xF0, 0x06, 0xFD, 0x07, 0x46, + 0x21, 0x46, 0x04, 0xF1, + 0x20, 0x00, 0x09, 0xF0, 0x00, 0xFD, 0x06, 0x46, 0x0D, 0xF0, 0xE6, 0xFC, + 0x00, 0x28, 0x28, 0x68, + 0x05, 0xD0, 0xB0, 0xF8, 0x93, 0x13, 0xB0, 0xF8, 0x8F, 0x03, 0x49, 0x43, + 0x04, 0xE0, 0xB0, 0xF8, + 0x91, 0x13, 0xB0, 0xF8, 0x8D, 0x03, 0x49, 0x43, 0x40, 0x43, 0x86, 0x42, + 0x06, 0xDD, 0x8F, 0x42, + 0x04, 0xDD, 0x34, 0xF8, 0x42, 0x0F, 0x40, 0xF0, 0x02, 0x00, 0x20, 0x80, + 0xBD, 0xE8, 0xF0, 0x81, + 0xF9, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xF8, 0xB5, 0x15, 0x46, + 0x0E, 0x46, 0x04, 0x46, + 0x0D, 0xF0, 0xC2, 0xFC, 0x01, 0x00, 0xF9, 0x48, 0x0B, 0xD0, 0x00, 0x68, + 0x90, 0xF8, 0xB4, 0x13, + 0xB0, 0xF8, 0xB7, 0x23, 0x01, 0xF0, 0x0F, 0x03, 0x0C, 0x09, 0xB0, 0xF8, + 0xB5, 0x13, 0x49, 0x43, + 0x10, 0xE0, 0x94, 0xF8, 0x3F, 0x11, 0x02, 0x29, 0x13, 0xD0, 0x00, 0x68, + 0x01, 0x29, 0x14, 0xD0, + 0x90, 0xF8, 0xB9, 0x13, 0xB0, 0xF8, 0xC0, 0x23, 0x01, 0xF0, 0x0F, 0x03, + 0x0C, 0x09, 0xB0, 0xF8, + 0xBE, 0x13, 0x49, 0x43, 0x52, 0x43, 0x30, 0x46, 0x00, 0x94, 0x09, 0xF0, + 0xC2, 0xFC, 0x2C, 0x60, + 0xF8, 0xBD, 0x00, 0x68, 0x90, 0xF8, 0xBA, 0x13, 0xEC, 0xE7, 0x90, 0xF8, + 0xBB, 0x13, 0xB0, 0xF8, + 0xC4, 0x23, 0x01, 0xF0, 0x0F, 0x03, 0x0C, 0x09, 0xB0, 0xF8, 0xC2, 0x13, + 0x49, 0x43, 0xE9, 0xE7, + 0x2D, 0xE9, 0xF8, 0x43, 0x04, 0x46, 0x90, 0xF8, 0x3E, 0x01, 0x88, 0x46, + 0x04, 0xF1, 0x78, 0x07, + 0x03, 0x28, 0x0B, 0xD0, 0xD9, 0x4E, 0x04, 0x28, 0x0D, 0xD0, 0x07, 0x28, + 0x3B, 0xD0, 0x08, 0x28, + 0x37, 0xD1, 0x38, 0x46, 0xBD, 0xE8, 0xF8, 0x43, 0x00, 0xF0, 0xC5, 0xBB, + 0x38, 0x46, 0xBD, 0xE8, + 0xF8, 0x43, 0x00, 0xF0, 0x8E, 0xBB, 0x20, 0x46, 0x0D, 0xF0, 0x83, 0xFC, + 0x18, 0xB1, 0x20, 0x46, + 0x0D, 0xF0, 0x7A, 0xFC, 0x1D, 0xE0, 0x04, 0xF1, 0x0C, 0x01, 0x08, 0x1D, + 0x09, 0xF0, 0x7B, 0xFC, + 0x01, 0x46, 0x6A, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0x97, 0xFF, 0x05, 0x46, + 0x94, 0xF8, 0x41, 0x01, + 0x80, 0xB9, 0x20, 0x46, 0x0D, 0xF0, 0x6A, 0xFC, 0x10, 0xB1, 0x00, 0x98, + 0x85, 0x42, 0x09, 0xDB, + 0x30, 0x68, 0xD4, 0xF8, 0x80, 0x10, 0x90, 0xF8, 0xBC, 0x03, 0x02, 0x09, + 0x28, 0x46, 0x09, 0xF0, + 0x85, 0xFC, 0x05, 0x46, 0x2A, 0x46, 0x41, 0x46, 0x38, 0x46, 0x00, 0xF0, + 0x64, 0xFB, 0xC4, 0xF8, + 0x80, 0x50, 0xBD, 0xE8, 0xF8, 0x83, 0x30, 0x68, 0x00, 0x24, 0x90, 0xF8, + 0x81, 0x13, 0x89, 0x07, + 0x0A, 0xD5, 0x90, 0xF8, 0xBD, 0x03, 0x00, 0xF0, 0x0F, 0x04, 0x0D, 0xF0, + 0x35, 0xFC, 0x18, 0xB1, + 0x30, 0x68, 0x90, 0xF8, 0xBD, 0x03, 0x04, 0x09, 0x22, 0x46, 0x41, 0x46, + 0x38, 0x46, 0xBD, 0xE8, + 0xF8, 0x43, 0x00, 0xF0, 0x60, 0xBB, 0x2D, 0xE9, 0xF0, 0x43, 0xDF, 0xF8, + 0xB0, 0x92, 0x4F, 0xF0, + 0x00, 0x0C, 0xB0, 0xF9, 0x02, 0x30, 0xD9, 0xF8, 0x00, 0x40, 0x67, 0x46, + 0x66, 0x46, 0x65, 0x46, + 0x00, 0x2B, 0x02, 0xDA, 0x4F, 0xF0, 0x01, 0x0C, 0x04, 0xE0, 0xB4, 0xF8, + 0x32, 0x80, 0x98, 0x45, + 0x00, 0xDA, 0x01, 0x27, 0xB0, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0x01, 0xDA, + 0x01, 0x26, 0x04, 0xE0, + 0xB4, 0xF8, 0x34, 0x80, 0x98, 0x45, 0x00, 0xDA, 0x01, 0x25, 0x00, 0x23, + 0xBC, 0xF1, 0x00, 0x0F, + 0x02, 0xD0, 0x0E, 0xB1, 0x43, 0x80, 0x03, 0xE0, 0x4F, 0xB1, 0x26, 0xB1, + 0x61, 0x8E, 0x38, 0xE0, + 0x03, 0x80, 0xBD, 0xE8, 0xF0, 0x83, 0x15, 0xB1, 0x62, 0x8E, 0x42, 0x80, + 0x04, 0xE0, 0xBC, 0xF1, + 0x00, 0x0F, 0x30, 0xD0, 0x2D, 0xB1, 0x43, 0x80, 0xD9, 0xF8, 0x00, 0x10, + 0x89, 0x8E, 0x01, 0x80, + 0xEF, 0xE7, 0xB2, 0xF8, 0x02, 0xC0, 0xBC, 0xF1, 0x00, 0x0F, 0x24, 0xD0, + 0x43, 0x80, 0xB1, 0xF9, + 0x02, 0x40, 0x67, 0x42, 0x2C, 0xE0, 0x00, 0xBF, 0x0C, 0xFB, 0x07, 0xFC, + 0x00, 0x2C, 0x00, 0xDA, + 0x64, 0x42, 0x9C, 0xFB, 0xF4, 0xF4, 0x0F, 0x88, 0x3C, 0x44, 0x04, 0x80, + 0x46, 0xB3, 0xB2, 0xF9, + 0x00, 0x40, 0x2C, 0xB3, 0xB1, 0xF9, 0x00, 0x50, 0xB2, 0xF9, 0x02, 0x20, + 0x6D, 0x42, 0x00, 0xD5, + 0x6D, 0x42, 0x6A, 0x43, 0x00, 0x2C, 0x00, 0xDA, 0x64, 0x42, 0x92, 0xFB, + 0xF4, 0xF2, 0x49, 0x88, + 0x11, 0x44, 0x41, 0x80, 0xC4, 0xE7, 0x00, 0x2F, 0xE8, 0xD0, 0x57, 0x88, + 0x00, 0x2F, 0xE5, 0xD0, + 0x64, 0x8E, 0x44, 0x80, 0xD9, 0xF8, 0x00, 0x40, 0xB1, 0xF9, 0x02, 0x70, + 0x64, 0x8E, 0xE7, 0x1B, + 0xB2, 0xF9, 0x02, 0x40, 0xB2, 0xF9, 0x00, 0xC0, 0x00, 0x2F, 0xCD, 0xDA, + 0x7F, 0x42, 0xCB, 0xE7, + 0x00, 0x2D, 0xAE, 0xD0, 0xB2, 0xF9, 0x00, 0x30, 0x00, 0x2B, 0xAA, 0xD0, + 0xD9, 0xF8, 0x00, 0x40, + 0xB1, 0xF9, 0x00, 0x60, 0xB2, 0xF9, 0x02, 0x20, 0xA4, 0x8E, 0xA4, 0x1B, + 0x00, 0xD5, 0x64, 0x42, + 0x62, 0x43, 0x00, 0x2B, 0x00, 0xDA, 0x5B, 0x42, 0x92, 0xFB, 0xF3, 0xF2, + 0x49, 0x88, 0x11, 0x44, + 0x41, 0x80, 0xA1, 0xE7, 0x2D, 0xE9, 0xF0, 0x5F, 0x04, 0x46, 0x61, 0x48, + 0x0D, 0x46, 0x00, 0x21, + 0x41, 0x80, 0x01, 0x80, 0xA0, 0xF1, 0x10, 0x08, 0x28, 0x68, 0xC8, 0xF8, + 0x00, 0x00, 0x17, 0x46, + 0x4F, 0xF0, 0x01, 0x0B, 0x46, 0x46, 0x29, 0x46, 0x20, 0x46, 0x00, 0xF0, + 0x67, 0xFF, 0xDF, 0xF8, + 0x5C, 0x91, 0x28, 0x68, 0x70, 0x60, 0xD9, 0xF8, 0x00, 0x00, 0x04, 0xF1, + 0x0C, 0x0A, 0x90, 0xF8, + 0x80, 0x03, 0x41, 0x07, 0x22, 0xD5, 0x94, 0xF8, 0x3E, 0x01, 0x04, 0xF1, + 0x84, 0x06, 0x02, 0x28, + 0x0A, 0xD0, 0x03, 0x28, 0x08, 0xD0, 0x04, 0x28, 0x0B, 0xD0, 0x06, 0x28, + 0x12, 0xD0, 0x07, 0x28, + 0x10, 0xD0, 0x08, 0x28, 0x0E, 0xD0, 0x11, 0xE0, 0x51, 0x46, 0x30, 0x46, + 0xFF, 0xF7, 0xC9, 0xFA, + 0x0C, 0xE0, 0x20, 0x46, 0x00, 0xF0, 0xDD, 0xF9, 0x02, 0x46, 0x29, 0x46, + 0x30, 0x46, 0xFF, 0xF7, + 0xE4, 0xFA, 0x03, 0xE0, 0x29, 0x46, 0x30, 0x46, 0xFF, 0xF7, 0xEB, 0xFB, + 0x29, 0x68, 0xC8, 0xF8, + 0x08, 0x10, 0xD9, 0xF8, 0x00, 0x00, 0x4E, 0x46, 0x90, 0xF8, 0x80, 0x03, + 0x00, 0x07, 0x09, 0xD5, + 0x94, 0xF8, 0x42, 0x00, 0x10, 0xF0, 0xC8, 0x0F, 0x35, 0xD0, 0x51, 0x46, + 0x04, 0xF1, 0xB0, 0x00, + 0x00, 0xF0, 0xF3, 0xFD, 0x29, 0x68, 0xC8, 0xF8, 0x0C, 0x10, 0x30, 0x68, + 0x90, 0xF8, 0x80, 0x13, + 0x49, 0x06, 0x0F, 0xD4, 0x90, 0xF8, 0x40, 0x14, 0x49, 0x06, 0x03, 0xD5, + 0x94, 0xF8, 0x42, 0x10, + 0x09, 0x07, 0x07, 0xD4, 0x90, 0xF8, 0x20, 0x04, 0x80, 0x07, 0x07, 0xD5, + 0x94, 0xF8, 0x42, 0x00, + 0x00, 0x06, 0x03, 0xD5, 0x29, 0x46, 0x20, 0x46, 0x01, 0xF0, 0xBC, 0xFC, + 0x30, 0x68, 0x90, 0xF8, + 0x80, 0x03, 0x80, 0x06, 0x03, 0xD5, 0x29, 0x46, 0x20, 0x46, 0xFF, 0xF7, + 0x89, 0xFE, 0x30, 0x68, + 0x90, 0xF8, 0x80, 0x03, 0x01, 0x07, 0x11, 0xD5, 0xC0, 0x06, 0x0F, 0xD5, + 0x94, 0xF8, 0x3E, 0x01, + 0x07, 0x28, 0x05, 0xD0, 0x0A, 0xE0, 0x29, 0x46, 0x20, 0x46, 0x00, 0xF0, + 0xB2, 0xF9, 0xC9, 0xE7, + 0x1B, 0x4A, 0x04, 0xF1, 0xF4, 0x01, 0x28, 0x46, 0xFF, 0xF7, 0xD5, 0xFE, + 0x30, 0x68, 0xB0, 0xF9, + 0x32, 0x10, 0xB5, 0xF9, 0x02, 0x00, 0x09, 0xF0, 0xD7, 0xFA, 0x68, 0x80, + 0x30, 0x68, 0xB0, 0xF9, + 0x34, 0x10, 0xB5, 0xF9, 0x00, 0x00, 0x09, 0xF0, 0xCF, 0xFA, 0x28, 0x80, + 0x94, 0xF8, 0x3E, 0x01, + 0x03, 0x28, 0x06, 0xD0, 0x04, 0x28, 0x08, 0xD0, 0x07, 0x28, 0x1B, 0xD0, + 0x08, 0x28, 0x19, 0xD0, + 0x1B, 0xE0, 0x38, 0x88, 0xA4, 0xF8, 0x50, 0x00, 0x17, 0xE0, 0x30, 0x68, + 0x34, 0xF8, 0x50, 0x2F, + 0x90, 0xF8, 0xBC, 0x03, 0x00, 0xF0, 0x0F, 0x01, 0xC1, 0xF1, 0x10, 0x00, + 0x4A, 0x43, 0x39, 0x88, + 0x01, 0xFB, 0x00, 0x20, 0x00, 0x09, 0x20, 0x80, 0x06, 0xE0, 0x00, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0x94, 0x05, 0x10, 0x00, 0xB4, 0xF8, 0x50, 0x00, 0x38, 0x80, 0x58, 0x46, + 0xBD, 0xE8, 0xF0, 0x9F, + 0x2D, 0xE9, 0xF3, 0x4F, 0xE4, 0x49, 0x83, 0xB0, 0x4F, 0xF0, 0x00, 0x08, + 0xC1, 0xF8, 0x00, 0x80, + 0xE2, 0x49, 0xE3, 0x4D, 0x83, 0x46, 0xC1, 0xF8, 0x00, 0x80, 0x85, 0xF8, + 0x00, 0x80, 0x46, 0x46, + 0xDF, 0xF8, 0x80, 0xA3, 0x4F, 0xF0, 0x01, 0x09, 0x00, 0xF5, 0x80, 0x57, + 0x77, 0xE0, 0x00, 0xBF, + 0xD7, 0xF8, 0xEC, 0x13, 0x09, 0xFA, 0x06, 0xF0, 0x01, 0x42, 0x6F, 0xD0, + 0x06, 0xEB, 0x06, 0x10, + 0x00, 0xEB, 0x80, 0x01, 0x0B, 0xEB, 0x81, 0x04, 0x94, 0xF8, 0x3E, 0x01, + 0x03, 0x28, 0x05, 0xD0, + 0x04, 0x28, 0x03, 0xD0, 0x07, 0x28, 0x01, 0xD0, 0x08, 0x28, 0x5F, 0xD1, + 0xE0, 0x68, 0x00, 0x90, + 0xB4, 0xF8, 0x4E, 0x00, 0xAD, 0xF8, 0x04, 0x00, 0x04, 0xF1, 0x0C, 0x01, + 0xCA, 0x4A, 0x08, 0x1D, + 0x00, 0xF0, 0x06, 0xF9, 0x01, 0xAA, 0x69, 0x46, 0x20, 0x46, 0xFF, 0xF7, + 0xF3, 0xFE, 0x02, 0x90, + 0xC6, 0x4A, 0x69, 0x46, 0x04, 0xF1, 0x24, 0x00, 0x00, 0xF0, 0xFA, 0xF8, + 0x94, 0xF8, 0x3F, 0x01, + 0x01, 0x28, 0x08, 0xD1, 0xC4, 0x48, 0x00, 0x78, 0x28, 0xB9, 0x94, 0xF8, + 0x3E, 0x01, 0x08, 0x28, + 0x01, 0xD0, 0x00, 0x20, 0x02, 0x90, 0xDA, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0x00, 0x04, 0xC0, 0x07, + 0x0E, 0xD0, 0x94, 0xF8, 0x42, 0x00, 0x40, 0x07, 0x02, 0xD5, 0x00, 0x20, + 0x02, 0x90, 0x07, 0xE0, + 0x94, 0xF8, 0x34, 0x01, 0x01, 0x28, 0x03, 0xD1, 0x20, 0x6A, 0x00, 0x90, + 0x84, 0xF8, 0x34, 0x81, + 0x94, 0xF8, 0x3F, 0x01, 0x03, 0x28, 0x09, 0xD1, 0x28, 0x78, 0x40, 0x1C, + 0xC0, 0xB2, 0x28, 0x70, + 0x94, 0xF8, 0x42, 0x10, 0x49, 0x07, 0x01, 0xD5, 0x40, 0x1E, 0x28, 0x70, + 0x00, 0x98, 0x60, 0x62, + 0xBD, 0xF8, 0x04, 0x00, 0xA4, 0xF8, 0x50, 0x00, 0x02, 0x98, 0x01, 0x28, + 0x0E, 0xD1, 0x00, 0x98, + 0xA0, 0x61, 0xBD, 0xF8, 0x04, 0x00, 0xA4, 0xF8, 0x52, 0x00, 0x04, 0x98, + 0x94, 0xF8, 0x4C, 0x21, + 0x00, 0x68, 0x09, 0xFA, 0x02, 0xF1, 0x08, 0x43, 0x04, 0x99, 0x08, 0x60, + 0x76, 0x1C, 0x97, 0xF9, + 0xF4, 0x03, 0xB0, 0x42, 0x84, 0xDA, 0xDA, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0x00, 0x04, 0x00, 0x07, + 0x0E, 0xD5, 0x29, 0x78, 0x9D, 0x48, 0x29, 0xB1, 0x9D, 0x49, 0x09, 0x78, + 0x01, 0x29, 0x01, 0xD1, + 0x80, 0xF8, 0x00, 0x90, 0xD7, 0xF8, 0xF0, 0x13, 0x00, 0x29, 0x01, 0xD1, + 0x80, 0xF8, 0x00, 0x80, + 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xF0, 0x47, 0x89, 0x46, + 0x06, 0x46, 0x00, 0x27, + 0x4F, 0xF0, 0x01, 0x08, 0x00, 0xF5, 0x80, 0x55, 0x3D, 0xE0, 0x00, 0xBF, + 0xD5, 0xF8, 0xEC, 0x13, + 0x08, 0xFA, 0x07, 0xF2, 0x11, 0x42, 0x35, 0xD0, 0x07, 0xEB, 0x07, 0x11, + 0x01, 0xEB, 0x81, 0x01, + 0x06, 0xEB, 0x81, 0x04, 0x94, 0xF8, 0x3E, 0x11, 0x03, 0x29, 0x05, 0xD0, + 0x04, 0x29, 0x03, 0xD0, + 0x07, 0x29, 0x01, 0xD0, 0x08, 0x29, 0x25, 0xD1, 0x94, 0xF8, 0x4C, 0x31, + 0xD9, 0xF8, 0x00, 0x20, + 0x08, 0xFA, 0x03, 0xF0, 0x02, 0x42, 0x1D, 0xD0, 0x03, 0x29, 0x03, 0xD1, + 0x21, 0x46, 0x30, 0x46, + 0x02, 0xF0, 0x7A, 0xF8, 0x94, 0xF9, 0x4D, 0x01, 0x00, 0x28, 0x13, 0xDB, + 0x94, 0xF8, 0x3F, 0x01, + 0x00, 0x21, 0x01, 0x28, 0x04, 0xD0, 0x02, 0x28, 0x04, 0xD0, 0x04, 0x28, + 0x04, 0xD0, 0x04, 0xE0, + 0x03, 0x21, 0x02, 0xE0, 0x04, 0x21, 0x00, 0xE0, 0x05, 0x21, 0x84, 0xF8, + 0x40, 0x11, 0x20, 0x46, + 0x08, 0xF0, 0x7D, 0xFC, 0x7F, 0x1C, 0x95, 0xF9, 0xF4, 0x03, 0xB8, 0x42, + 0xBE, 0xDA, 0x00, 0x24, + 0x47, 0x46, 0x24, 0xE0, 0xD5, 0xF8, 0xEC, 0x03, 0x07, 0xFA, 0x04, 0xF1, + 0x08, 0x42, 0x1D, 0xD0, + 0x04, 0xEB, 0x04, 0x10, 0x00, 0xEB, 0x80, 0x00, 0x06, 0xEB, 0x80, 0x08, + 0x98, 0xF8, 0x3E, 0x01, + 0x08, 0x28, 0x13, 0xD1, 0x98, 0xF8, 0x4C, 0x21, 0xD9, 0xF8, 0x00, 0x10, + 0x07, 0xFA, 0x02, 0xF0, + 0x01, 0x42, 0x07, 0xD0, 0x98, 0xF9, 0x4D, 0x01, 0x00, 0x28, 0x03, 0xDB, + 0x41, 0x46, 0x30, 0x46, + 0x02, 0xF0, 0x55, 0xF8, 0x41, 0x46, 0x30, 0x46, 0x02, 0xF0, 0x18, 0xF8, + 0x64, 0x1C, 0x95, 0xF9, + 0xF4, 0x03, 0xA0, 0x42, 0xD6, 0xDA, 0xBD, 0xE8, 0xF0, 0x87, 0x53, 0x49, + 0x10, 0xB5, 0x00, 0x20, + 0x08, 0x60, 0x52, 0x49, 0x08, 0x60, 0xFF, 0xF7, 0x03, 0xF9, 0x00, 0xF0, + 0x2F, 0xFC, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0xF0, 0xAD, 0xB8, 0x38, 0xB5, 0x04, 0x46, 0x00, 0x20, + 0x00, 0x90, 0x69, 0x46, + 0x20, 0x46, 0xFF, 0xF7, 0xC5, 0xFE, 0x69, 0x46, 0x20, 0x46, 0xFF, 0xF7, + 0x6C, 0xFF, 0x38, 0xBD, + 0x10, 0xB5, 0x14, 0x46, 0x09, 0xF0, 0x97, 0xF9, 0x21, 0x68, 0x81, 0x42, + 0x00, 0xDA, 0x20, 0x60, + 0x10, 0xBD, 0x10, 0xB5, 0x02, 0x46, 0x43, 0x49, 0xB2, 0xF8, 0x42, 0x30, + 0x4F, 0xF0, 0xFF, 0x30, + 0x09, 0x68, 0x5C, 0x06, 0x03, 0xD5, 0x91, 0xF8, 0xA5, 0x03, 0x00, 0x09, + 0x10, 0xBD, 0x1C, 0x07, + 0x02, 0xD5, 0x91, 0xF8, 0x4F, 0x04, 0x03, 0xE0, 0x1B, 0x06, 0x04, 0xD5, + 0x91, 0xF8, 0x2A, 0x04, + 0x00, 0xF0, 0x0F, 0x00, 0x10, 0xBD, 0x92, 0xF8, 0x3F, 0x21, 0x01, 0x2A, + 0x06, 0xD0, 0x39, 0x4A, + 0x12, 0x78, 0x01, 0x2A, 0xF6, 0xD9, 0x91, 0xF9, 0xAA, 0x03, 0x10, 0xBD, + 0x91, 0xF8, 0xA5, 0x03, + 0xEE, 0xE7, 0x30, 0xB4, 0x0C, 0x46, 0x90, 0xF8, 0x3E, 0x11, 0x00, 0xF1, + 0xB0, 0x03, 0x03, 0x29, + 0x23, 0xD0, 0x04, 0x29, 0x03, 0xD0, 0x06, 0x29, 0x01, 0xD0, 0x07, 0x29, + 0x41, 0xD1, 0x29, 0x4A, + 0x12, 0x68, 0x92, 0xF8, 0x80, 0x23, 0xD2, 0x06, 0x2D, 0xD5, 0x90, 0xF8, + 0x5B, 0x20, 0x90, 0xF8, + 0x5A, 0x50, 0x52, 0x1B, 0xC0, 0xF8, 0x24, 0x21, 0x90, 0xF8, 0x5D, 0x20, + 0x90, 0xF8, 0x5C, 0x50, + 0x52, 0x1B, 0xC0, 0xF8, 0x28, 0x21, 0x82, 0x6B, 0xC0, 0xF8, 0x20, 0x21, + 0x22, 0x4A, 0x07, 0x29, + 0x12, 0x88, 0xC0, 0xF8, 0x2C, 0x21, 0x06, 0xD0, 0x0F, 0xE0, 0x00, 0xF1, + 0x0C, 0x01, 0x30, 0xBC, + 0x18, 0x46, 0x00, 0xF0, 0xDA, 0xBB, 0x90, 0xF8, 0x31, 0x11, 0x03, 0x29, + 0x05, 0xD9, 0x21, 0x46, + 0x30, 0xBC, 0x1A, 0x4A, 0x18, 0x46, 0x00, 0xF0, 0x68, 0xBC, 0x90, 0xF8, + 0x31, 0x11, 0x49, 0x1C, + 0x80, 0xF8, 0x31, 0x11, 0x03, 0xE0, 0x90, 0xF8, 0x31, 0x21, 0x03, 0x2A, + 0x04, 0xD9, 0x21, 0x46, + 0x30, 0xBC, 0x18, 0x46, 0x00, 0xF0, 0x26, 0xBC, 0x04, 0x29, 0x04, 0xD0, + 0x00, 0x21, 0x80, 0xF8, + 0x31, 0x11, 0x30, 0xBC, 0x70, 0x47, 0x52, 0x1C, 0x80, 0xF8, 0x31, 0x21, + 0x21, 0x46, 0x30, 0xBC, + 0x18, 0x46, 0x00, 0xF0, 0x00, 0xBC, 0x00, 0x00, 0x24, 0x07, 0x10, 0x00, + 0x28, 0x07, 0x10, 0x00, + 0x20, 0x07, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xF9, 0x06, 0x10, 0x00, + 0xA5, 0x06, 0x10, 0x00, + 0xA4, 0x06, 0x10, 0x00, 0xFA, 0x06, 0x10, 0x00, 0x78, 0x06, 0x10, 0x00, + 0x94, 0x05, 0x10, 0x00, + 0x70, 0x47, 0x00, 0xF0, 0x35, 0xB8, 0x7C, 0xB5, 0x04, 0x46, 0x15, 0x46, + 0x0E, 0x46, 0x68, 0x46, + 0x00, 0xF0, 0x2E, 0xF8, 0x01, 0x99, 0x2A, 0x46, 0x60, 0x68, 0x00, 0xF0, + 0x3B, 0xF8, 0x60, 0x60, + 0x00, 0x99, 0x2A, 0x46, 0x20, 0x68, 0x00, 0xF0, 0x35, 0xF8, 0x20, 0x60, + 0x21, 0x46, 0x30, 0x46, + 0x00, 0xF0, 0x27, 0xF8, 0x7C, 0xBD, 0x7C, 0xB5, 0x04, 0x46, 0x15, 0x46, + 0x0E, 0x46, 0x68, 0x46, + 0x00, 0xF0, 0x16, 0xF8, 0x01, 0x99, 0x2A, 0x46, 0x60, 0x68, 0x00, 0xF0, + 0x23, 0xF8, 0x60, 0x60, + 0x00, 0x99, 0x2A, 0x46, 0x20, 0x68, 0x00, 0xF0, 0x1D, 0xF8, 0x20, 0x60, + 0x21, 0x46, 0x30, 0x46, + 0x00, 0xF0, 0x0F, 0xF8, 0x7C, 0xBD, 0x0A, 0x46, 0x01, 0x46, 0x10, 0x46, + 0x00, 0xF0, 0x09, 0xB8, + 0xB1, 0xF9, 0x02, 0x20, 0x12, 0x02, 0x42, 0x60, 0xB1, 0xF9, 0x00, 0x10, + 0x09, 0x02, 0x01, 0x60, + 0x70, 0x47, 0x4A, 0x68, 0x80, 0x32, 0x12, 0x12, 0x42, 0x80, 0x09, 0x68, + 0x80, 0x31, 0x09, 0x12, + 0x01, 0x80, 0x70, 0x47, 0xC2, 0xF1, 0x10, 0x03, 0x50, 0x43, 0x01, 0xFB, + 0x03, 0x00, 0x00, 0x11, + 0x70, 0x47, 0x00, 0x00, 0x2D, 0xE9, 0xF0, 0x41, 0xFE, 0x4A, 0x12, 0x68, + 0x51, 0xB3, 0x51, 0x8E, + 0x92, 0xF8, 0x30, 0x30, 0x82, 0x6F, 0x04, 0x6F, 0xC0, 0x6F, 0x64, 0x26, + 0x40, 0x00, 0x00, 0xFB, + 0x02, 0x40, 0x48, 0x43, 0xA0, 0xFB, 0x00, 0x25, 0x00, 0x21, 0x01, 0xFB, + 0x00, 0x55, 0x00, 0xFB, + 0x01, 0x51, 0xA2, 0xFB, 0x06, 0x07, 0x00, 0x25, 0x01, 0xFB, 0x06, 0x71, + 0x02, 0xFB, 0x05, 0x11, + 0x5C, 0x43, 0x22, 0x46, 0x2B, 0x46, 0x0C, 0xF0, 0x72, 0xFE, 0x22, 0x46, + 0x00, 0x23, 0x0C, 0xF0, + 0x6E, 0xFE, 0xED, 0x4B, 0x00, 0x22, 0x1B, 0x1A, 0x8A, 0x41, 0x01, 0xD2, + 0xEA, 0x48, 0x00, 0x21, + 0xBD, 0xE8, 0xF0, 0x81, 0x91, 0x8E, 0x92, 0xF8, 0x31, 0x30, 0x42, 0x6F, + 0xD3, 0xE7, 0x7C, 0xB5, + 0x04, 0x46, 0xE6, 0x48, 0xB4, 0xF9, 0x02, 0x10, 0x00, 0x78, 0x01, 0x28, + 0x30, 0xD0, 0xB4, 0xF9, + 0x06, 0x00, 0xB4, 0xF9, 0x0A, 0x20, 0x09, 0x1A, 0x80, 0x1A, 0x08, 0x1A, + 0x01, 0x90, 0xB4, 0xF9, + 0x00, 0x10, 0xB4, 0xF9, 0x04, 0x00, 0xB4, 0xF9, 0x08, 0x20, 0x09, 0x1A, + 0x80, 0x1A, 0x08, 0x1A, + 0xD8, 0x49, 0x00, 0x90, 0x20, 0x6C, 0x09, 0x68, 0x01, 0x9B, 0x91, 0xF8, + 0xB3, 0x23, 0x50, 0x43, + 0xC2, 0xF1, 0x80, 0x02, 0x53, 0x43, 0xC2, 0x17, 0x00, 0xEB, 0x52, 0x60, + 0x03, 0xEB, 0xE0, 0x10, + 0x20, 0x64, 0x91, 0xF8, 0xB3, 0x13, 0xE0, 0x6B, 0x00, 0x9A, 0x48, 0x43, + 0xC1, 0xF1, 0x80, 0x01, + 0x4A, 0x43, 0xC1, 0x17, 0x00, 0xEB, 0x51, 0x60, 0x02, 0xEB, 0xE0, 0x10, + 0xE0, 0x63, 0x7C, 0xBD, + 0xB4, 0xF9, 0x46, 0x00, 0xB4, 0xF9, 0x4A, 0x20, 0x09, 0x1A, 0x80, 0x1A, + 0x08, 0x1A, 0x01, 0x90, + 0xB4, 0xF9, 0x00, 0x10, 0xB4, 0xF9, 0x44, 0x00, 0xB4, 0xF9, 0x48, 0x20, + 0x09, 0x1A, 0x80, 0x1A, + 0x08, 0x1A, 0x00, 0x90, 0x04, 0xF1, 0x50, 0x00, 0x03, 0x22, 0x69, 0x46, + 0x05, 0x46, 0x09, 0xF0, + 0x08, 0xF8, 0x94, 0xF8, 0x80, 0x00, 0x03, 0x28, 0x02, 0xD2, 0x40, 0x1C, + 0x84, 0xF8, 0x80, 0x00, + 0xC2, 0xB2, 0x29, 0x46, 0x04, 0xF1, 0x68, 0x00, 0x00, 0xF0, 0x98, 0xFB, + 0x7C, 0xBD, 0x2D, 0xE9, + 0xF0, 0x4F, 0x89, 0xB0, 0x00, 0x26, 0x05, 0x96, 0x06, 0x96, 0x07, 0x96, + 0x01, 0x24, 0x0D, 0xF1, + 0x14, 0x08, 0x08, 0x96, 0x02, 0x25, 0xCD, 0xE9, 0x01, 0x48, 0x07, 0x46, + 0xCD, 0xE9, 0x03, 0x54, + 0x00, 0xF1, 0x0C, 0x03, 0xAD, 0x48, 0x9B, 0x46, 0x2A, 0x46, 0x29, 0x46, + 0x20, 0x30, 0x00, 0x95, + 0x08, 0xF0, 0x70, 0xFF, 0xDF, 0xF8, 0xA4, 0x92, 0x4F, 0xF4, 0x80, 0x7A, + 0x99, 0xF8, 0x00, 0x00, + 0x01, 0x28, 0x48, 0xD0, 0x38, 0x6C, 0x00, 0x90, 0x01, 0x23, 0x02, 0x22, + 0x07, 0xA9, 0x09, 0xF1, + 0x08, 0x00, 0x08, 0xF0, 0x36, 0xFF, 0x07, 0xA9, 0x01, 0x23, 0x02, 0x22, + 0x08, 0x46, 0xCD, 0xF8, + 0x00, 0xA0, 0x08, 0xF0, 0x20, 0xFF, 0x02, 0x23, 0x5A, 0x46, 0x07, 0xA9, + 0x05, 0xA8, 0x00, 0x94, + 0x08, 0xF0, 0x34, 0xFF, 0x05, 0x96, 0x06, 0x96, 0x07, 0x96, 0x08, 0x96, + 0xCD, 0xE9, 0x01, 0x48, + 0xCD, 0xE9, 0x03, 0x54, 0x95, 0x48, 0x07, 0xF1, 0x14, 0x03, 0x00, 0x95, + 0x02, 0x22, 0x1D, 0x46, + 0x11, 0x46, 0x20, 0x30, 0x08, 0xF0, 0x3E, 0xFF, 0x99, 0xF8, 0x00, 0x00, + 0x01, 0x28, 0x1F, 0xD0, + 0xF8, 0x6B, 0x00, 0x90, 0x8D, 0x48, 0x01, 0x23, 0x02, 0x22, 0x07, 0xA9, + 0x08, 0x30, 0x08, 0xF0, + 0x08, 0xFF, 0x07, 0xA9, 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0xCD, 0xF8, + 0x00, 0xA0, 0x08, 0xF0, + 0xF2, 0xFE, 0x02, 0x23, 0x2A, 0x46, 0x07, 0xA9, 0x05, 0xA8, 0x00, 0x94, + 0x08, 0xF0, 0x06, 0xFF, + 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDD, 0xE9, 0x05, 0x01, 0xC7, 0xE9, + 0x03, 0x01, 0xC9, 0xE7, + 0xDD, 0xE9, 0x05, 0x01, 0xC7, 0xE9, 0x05, 0x01, 0xF2, 0xE7, 0x2D, 0xE9, + 0xF0, 0x4F, 0x8D, 0xB0, + 0x00, 0x26, 0x02, 0x24, 0x05, 0x96, 0x06, 0x96, 0x07, 0x96, 0x08, 0x96, + 0x09, 0x96, 0x0A, 0x96, + 0x0B, 0x96, 0x05, 0xAF, 0x0C, 0x96, 0xCD, 0xE9, 0x01, 0x47, 0x05, 0x46, + 0x73, 0x48, 0x05, 0xF1, + 0x1C, 0x03, 0x03, 0x94, 0x04, 0x94, 0x9B, 0x46, 0x22, 0x46, 0x21, 0x46, + 0x20, 0x30, 0x00, 0x94, + 0x08, 0xF0, 0xF8, 0xFE, 0x0D, 0xF1, 0x24, 0x0A, 0xCD, 0xE9, 0x01, 0x4A, + 0x6B, 0x4B, 0x02, 0x22, + 0x03, 0x94, 0x04, 0x94, 0x30, 0x33, 0x11, 0x46, 0x05, 0xA8, 0x00, 0x94, + 0x08, 0xF0, 0xEA, 0xFE, + 0xDF, 0xF8, 0x98, 0x81, 0x4F, 0xF0, 0x04, 0x09, 0x98, 0xF8, 0x00, 0x00, + 0x01, 0x28, 0x12, 0xD1, + 0xE8, 0x6E, 0x02, 0x23, 0x08, 0xF1, 0x60, 0x01, 0x00, 0x90, 0x1A, 0x46, + 0xA1, 0xF1, 0x10, 0x00, + 0x08, 0xF0, 0xAF, 0xFE, 0x02, 0x23, 0x08, 0xF1, 0x60, 0x01, 0x1A, 0x46, + 0x08, 0x46, 0xCD, 0xF8, + 0x00, 0x90, 0x08, 0xF0, 0x98, 0xFE, 0x59, 0x49, 0x02, 0x23, 0x5A, 0x46, + 0x60, 0x31, 0x09, 0xA8, + 0x00, 0x94, 0x08, 0xF0, 0xAB, 0xFE, 0x05, 0x96, 0x06, 0x96, 0x07, 0x96, + 0x08, 0x96, 0x09, 0x96, + 0x0A, 0x96, 0x0B, 0x96, 0x0C, 0x96, 0xCD, 0xE9, 0x01, 0x47, 0x50, 0x48, + 0x05, 0xF1, 0x2C, 0x03, + 0x02, 0x22, 0x03, 0x94, 0x04, 0x94, 0x1E, 0x46, 0x11, 0x46, 0x20, 0x30, + 0x00, 0x94, 0x08, 0xF0, + 0xB1, 0xFE, 0xCD, 0xE9, 0x01, 0x4A, 0x49, 0x4B, 0x02, 0x22, 0x03, 0x94, + 0x04, 0x94, 0x30, 0x33, + 0x11, 0x46, 0x05, 0xA8, 0x00, 0x94, 0x08, 0xF0, 0xA5, 0xFE, 0x98, 0xF8, + 0x00, 0x00, 0x01, 0x28, + 0x12, 0xD1, 0x42, 0x49, 0xA8, 0x6E, 0x02, 0x23, 0x60, 0x31, 0x00, 0x90, + 0x1A, 0x46, 0xA1, 0xF1, + 0x10, 0x00, 0x08, 0xF0, 0x6E, 0xFE, 0x3D, 0x49, 0x02, 0x23, 0x60, 0x31, + 0x1A, 0x46, 0x08, 0x46, + 0xCD, 0xF8, 0x00, 0x90, 0x08, 0xF0, 0x57, 0xFE, 0x38, 0x49, 0x02, 0x23, + 0x32, 0x46, 0x60, 0x31, + 0x09, 0xA8, 0x00, 0x94, 0x08, 0xF0, 0x6A, 0xFE, 0x0D, 0xB0, 0x62, 0xE7, + 0x2D, 0xE9, 0xF0, 0x4F, + 0x89, 0xB0, 0x00, 0x26, 0x01, 0x24, 0x05, 0x96, 0x06, 0x96, 0x0D, 0xF1, + 0x14, 0x0A, 0x07, 0x96, + 0xCD, 0xE9, 0x01, 0x4A, 0x05, 0x46, 0x00, 0xF1, 0x0C, 0x03, 0x4F, 0xF0, + 0x02, 0x09, 0x2B, 0x48, + 0x93, 0x46, 0x0F, 0x46, 0x03, 0x94, 0x98, 0x46, 0x4A, 0x46, 0x21, 0x46, + 0x10, 0x30, 0xCD, 0xF8, + 0x00, 0x90, 0x04, 0x94, 0x08, 0xF0, 0x66, 0xFE, 0xB5, 0xF9, 0x02, 0x00, + 0x05, 0x99, 0x01, 0x23, + 0x40, 0x1A, 0x05, 0x90, 0x00, 0x90, 0x02, 0x22, 0x06, 0xA9, 0x38, 0x46, + 0x08, 0xF0, 0x31, 0xFE, + 0x64, 0x27, 0x41, 0x46, 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0x00, 0x97, + 0x08, 0xF0, 0x29, 0xFE, + 0x42, 0x46, 0x02, 0x23, 0x06, 0xA9, 0x10, 0x46, 0x00, 0x94, 0x08, 0xF0, + 0x2F, 0xFE, 0x41, 0x46, + 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0x00, 0x97, 0x08, 0xF0, 0x0D, 0xFE, + 0x05, 0x96, 0x06, 0x96, + 0x07, 0x96, 0xCD, 0xE9, 0x01, 0x4A, 0x11, 0x48, 0x05, 0xF1, 0x14, 0x03, + 0x03, 0x94, 0x1E, 0x46, + 0x02, 0x22, 0x01, 0x21, 0x10, 0x30, 0xCD, 0xF8, 0x00, 0x90, 0x04, 0x94, + 0x08, 0xF0, 0x32, 0xFE, + 0xB5, 0xF9, 0x00, 0x00, 0x05, 0x99, 0x01, 0x23, 0x40, 0x1A, 0x05, 0x90, + 0x00, 0x90, 0x02, 0x22, + 0x06, 0xA9, 0x58, 0x46, 0x08, 0xF0, 0xFD, 0xFD, 0x01, 0x23, 0x31, 0x46, + 0x02, 0x22, 0x08, 0x46, + 0x00, 0x97, 0x05, 0xE0, 0x4C, 0x07, 0x10, 0x00, 0x40, 0x42, 0x0F, 0x00, + 0x98, 0x05, 0x10, 0x00, + 0x08, 0xF0, 0xEF, 0xFD, 0x32, 0x46, 0x02, 0x23, 0x06, 0xA9, 0x10, 0x46, + 0x00, 0x94, 0x08, 0xF0, + 0xF5, 0xFD, 0x31, 0x46, 0x01, 0x23, 0x02, 0x22, 0x08, 0x46, 0x00, 0x97, + 0x08, 0xF0, 0xD3, 0xFD, + 0xE6, 0xE6, 0x2D, 0xE9, 0xF7, 0x4F, 0x8A, 0xB0, 0x00, 0x26, 0x05, 0x96, + 0x06, 0x96, 0x07, 0x96, + 0x08, 0x96, 0x01, 0x24, 0x4F, 0xF0, 0x02, 0x09, 0x0D, 0xF1, 0x14, 0x0A, + 0x09, 0x96, 0xCD, 0xE9, + 0x01, 0x4A, 0xCD, 0xE9, 0x03, 0x94, 0x07, 0x46, 0x07, 0xF1, 0x1C, 0x00, + 0x4D, 0x46, 0xFD, 0x4B, + 0x4A, 0x46, 0x49, 0x46, 0x80, 0x46, 0xCD, 0xF8, 0x00, 0x90, 0x08, 0xF0, + 0xEB, 0xFD, 0x07, 0xA8, + 0xCD, 0xE9, 0x01, 0x50, 0xF7, 0x48, 0xCD, 0xE9, 0x03, 0x45, 0x43, 0x46, + 0x02, 0x22, 0x01, 0x21, + 0x08, 0x38, 0x00, 0x95, 0x08, 0xF0, 0xDE, 0xFD, 0x0D, 0xF1, 0x24, 0x0B, + 0xCD, 0xE9, 0x01, 0x4B, + 0x03, 0x94, 0xF0, 0x4B, 0x02, 0x22, 0x01, 0x21, 0x07, 0xA8, 0x00, 0x95, + 0x04, 0x94, 0x08, 0xF0, + 0xD1, 0xFD, 0xEC, 0x4D, 0x18, 0x3D, 0x28, 0x78, 0x01, 0x28, 0x04, 0xD1, + 0x01, 0x21, 0x38, 0x46, + 0xFF, 0xF7, 0xA8, 0xFD, 0x68, 0x60, 0x09, 0x98, 0x69, 0x68, 0x4F, 0xF0, + 0x64, 0x08, 0x08, 0x44, + 0x05, 0xA9, 0x09, 0x90, 0x01, 0x23, 0x02, 0x22, 0xCD, 0xF8, 0x00, 0x80, + 0x08, 0x46, 0x08, 0xF0, + 0x90, 0xFD, 0x09, 0x98, 0x00, 0x90, 0x01, 0x23, 0x02, 0x22, 0x05, 0xA8, + 0x0B, 0x99, 0x08, 0xF0, + 0x7A, 0xFD, 0x07, 0x96, 0x08, 0x96, 0x05, 0x96, 0x06, 0x96, 0x09, 0x96, + 0xCD, 0xE9, 0x01, 0x4A, + 0xCD, 0xE9, 0x03, 0x94, 0x4E, 0x46, 0x02, 0x22, 0x07, 0xF1, 0x2C, 0x00, + 0xCD, 0xF8, 0x00, 0x90, + 0xD4, 0x4B, 0x11, 0x46, 0x81, 0x46, 0x08, 0xF0, 0x9D, 0xFD, 0x07, 0xA8, + 0xCD, 0xE9, 0x01, 0x60, + 0xCD, 0xE9, 0x03, 0x46, 0xCF, 0x48, 0x4B, 0x46, 0x02, 0x22, 0x01, 0x21, + 0x08, 0x38, 0x00, 0x96, + 0x08, 0xF0, 0x90, 0xFD, 0xCD, 0xE9, 0x01, 0x4B, 0x03, 0x94, 0xCA, 0x4B, + 0x02, 0x22, 0x01, 0x21, + 0x07, 0xA8, 0x00, 0x96, 0x04, 0x94, 0x08, 0xF0, 0x85, 0xFD, 0x28, 0x78, + 0x01, 0x28, 0x04, 0xD1, + 0x00, 0x21, 0x38, 0x46, 0xFF, 0xF7, 0x5E, 0xFD, 0x68, 0x60, 0x09, 0x98, + 0x69, 0x68, 0x01, 0x23, + 0x08, 0x44, 0x05, 0xA9, 0x09, 0x90, 0x02, 0x22, 0xCD, 0xF8, 0x00, 0x80, + 0x08, 0x46, 0x08, 0xF0, + 0x48, 0xFD, 0x09, 0x98, 0x00, 0x90, 0x01, 0x23, 0x02, 0x22, 0x05, 0xA8, + 0x0C, 0x99, 0x08, 0xF0, + 0x32, 0xFD, 0xE1, 0xE6, 0x2D, 0xE9, 0xF7, 0x4F, 0x8E, 0xB0, 0x00, 0x25, + 0x05, 0x95, 0x06, 0x95, + 0x07, 0x95, 0x02, 0x24, 0x08, 0x95, 0x09, 0x95, 0x0A, 0x95, 0x0B, 0x95, + 0x05, 0xAF, 0x0C, 0x95, + 0xCD, 0xE9, 0x01, 0x47, 0x8C, 0x46, 0x4F, 0xF0, 0x01, 0x0A, 0xAE, 0x4B, + 0x06, 0x46, 0x03, 0x94, + 0x08, 0x3B, 0x52, 0x46, 0x21, 0x46, 0x60, 0x46, 0xCD, 0xF8, 0x00, 0xA0, + 0x04, 0x94, 0x08, 0xF0, + 0x49, 0xFD, 0xA8, 0x48, 0x05, 0xAA, 0x02, 0x23, 0x11, 0x46, 0x28, 0x30, + 0x00, 0x94, 0x08, 0xF0, + 0x33, 0xFD, 0x0D, 0xF1, 0x24, 0x08, 0xCD, 0xE9, 0x01, 0x48, 0x06, 0xF1, + 0x1C, 0x03, 0x02, 0x22, + 0x03, 0x94, 0x04, 0x94, 0x9B, 0x46, 0x11, 0x46, 0x05, 0xA8, 0x00, 0x94, + 0x08, 0xF0, 0x32, 0xFD, + 0x4F, 0xF0, 0x64, 0x09, 0x02, 0x23, 0x1A, 0x46, 0x59, 0x46, 0x09, 0xA8, + 0xCD, 0xF8, 0x00, 0x90, + 0x08, 0xF0, 0xF1, 0xFC, 0x05, 0x95, 0x06, 0x95, 0x07, 0x95, 0x08, 0x95, + 0x09, 0x95, 0x0A, 0x95, + 0x0B, 0x95, 0x0C, 0x95, 0xCD, 0xE9, 0x01, 0x47, 0x92, 0x4B, 0x03, 0x94, + 0x08, 0x3B, 0x01, 0x22, + 0x02, 0x21, 0xCD, 0xF8, 0x00, 0xA0, 0x04, 0x94, 0x10, 0x98, 0x08, 0xF0, + 0x13, 0xFD, 0x8D, 0x48, + 0x05, 0xAA, 0x02, 0x23, 0x11, 0x46, 0x28, 0x30, 0x00, 0x94, 0x08, 0xF0, + 0xFD, 0xFC, 0xCD, 0xE9, + 0x01, 0x48, 0x03, 0x94, 0x04, 0x94, 0x06, 0xF1, 0x2C, 0x03, 0x00, 0x94, + 0x02, 0x22, 0x1C, 0x46, + 0x11, 0x46, 0x05, 0xA8, 0x08, 0xF0, 0xFE, 0xFC, 0x02, 0x23, 0x1A, 0x46, + 0x21, 0x46, 0x09, 0xA8, + 0xCD, 0xF8, 0x00, 0x90, 0x08, 0xF0, 0xBF, 0xFC, 0x11, 0xB0, 0xD2, 0xE5, + 0x38, 0xB5, 0x7E, 0x48, + 0x7C, 0x4C, 0x01, 0x68, 0x18, 0x3C, 0x91, 0xF8, 0x80, 0x03, 0xC0, 0xF3, + 0x00, 0x12, 0x22, 0x70, + 0xB1, 0xF8, 0xB1, 0x03, 0x1A, 0xB1, 0x64, 0x21, 0x48, 0x43, 0x0D, 0x46, + 0x01, 0xE0, 0xD1, 0xF8, + 0xAD, 0x53, 0x74, 0x49, 0x80, 0x08, 0x02, 0x23, 0x48, 0x31, 0x00, 0x90, + 0x1A, 0x46, 0xA1, 0xF1, + 0x10, 0x00, 0x08, 0xF0, 0xAE, 0xFC, 0x65, 0x60, 0x38, 0xBD, 0xF8, 0xB5, + 0x04, 0x46, 0x08, 0x68, + 0x20, 0x60, 0x48, 0x68, 0x60, 0x60, 0x88, 0x68, 0xA0, 0x60, 0x00, 0x25, + 0x25, 0x64, 0xE5, 0x63, + 0xB1, 0xF9, 0x02, 0x00, 0xC4, 0xE9, 0x03, 0x05, 0xB1, 0xF9, 0x00, 0x00, + 0xC4, 0xE9, 0x05, 0x05, + 0x64, 0x48, 0x18, 0x38, 0x01, 0x78, 0x01, 0x29, 0x09, 0xD0, 0x60, 0x30, + 0x1C, 0x34, 0x0F, 0xC8, + 0x0F, 0xC4, 0x84, 0xE8, 0x0F, 0x00, 0x2C, 0x3C, 0x84, 0xF8, 0x81, 0x50, + 0xF8, 0xBD, 0x50, 0x30, + 0x1C, 0x34, 0x0F, 0xC8, 0x0F, 0xC4, 0x5C, 0x4E, 0x0F, 0xC4, 0x30, 0x68, + 0x64, 0x21, 0x02, 0x23, + 0xB0, 0xF8, 0xB1, 0x03, 0x1A, 0x46, 0x48, 0x43, 0x80, 0x08, 0xA4, 0xF1, + 0x20, 0x01, 0x00, 0x90, + 0x08, 0x46, 0x3C, 0x3C, 0x08, 0xF0, 0x75, 0xFC, 0x30, 0x68, 0x64, 0x21, + 0x02, 0x23, 0xB0, 0xF8, + 0xB1, 0x03, 0x1A, 0x46, 0x48, 0x43, 0x80, 0x08, 0x04, 0xF1, 0x2C, 0x01, + 0x00, 0x90, 0x08, 0x46, + 0x08, 0xF0, 0x67, 0xFC, 0x94, 0xE8, 0x07, 0x00, 0x04, 0xF1, 0x44, 0x03, + 0x83, 0xE8, 0x07, 0x00, + 0x84, 0xF8, 0x80, 0x50, 0xD0, 0xE7, 0x10, 0xB5, 0x04, 0x46, 0x03, 0x22, + 0x08, 0xF0, 0xDC, 0xFC, + 0x20, 0x46, 0xFF, 0xF7, 0x94, 0xFC, 0xB4, 0xF9, 0x02, 0x00, 0xE0, 0x60, + 0xB4, 0xF9, 0x06, 0x10, + 0x40, 0x1A, 0x20, 0x61, 0xB4, 0xF9, 0x00, 0x00, 0x60, 0x61, 0xB4, 0xF9, + 0x04, 0x10, 0x40, 0x1A, + 0xA0, 0x61, 0x10, 0xBD, 0x7F, 0xB5, 0x0D, 0x46, 0x04, 0x46, 0x03, 0x22, + 0x08, 0xF0, 0xC4, 0xFC, + 0x20, 0x46, 0xFF, 0xF7, 0x7C, 0xFC, 0x20, 0x46, 0xFF, 0xF7, 0xD9, 0xFC, + 0x20, 0x46, 0xFF, 0xF7, + 0x4C, 0xFD, 0x00, 0x20, 0x00, 0x90, 0x01, 0x90, 0x02, 0x90, 0x03, 0x90, + 0x02, 0xAA, 0x69, 0x46, + 0x20, 0x46, 0xFF, 0xF7, 0x4E, 0xFE, 0x02, 0xAA, 0x69, 0x46, 0x20, 0x46, + 0xFF, 0xF7, 0xCE, 0xFD, + 0x02, 0xAA, 0x69, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0xE5, 0xFE, 0xA0, 0x89, + 0x68, 0x80, 0xA0, 0x8A, + 0x28, 0x80, 0x28, 0x48, 0x18, 0x38, 0x00, 0x78, 0x01, 0x28, 0x05, 0xD1, + 0x03, 0x22, 0x29, 0x46, + 0x04, 0xF1, 0x44, 0x00, 0x08, 0xF0, 0x98, 0xFC, 0x7F, 0xBD, 0x2D, 0xE9, + 0xF0, 0x47, 0x06, 0x46, + 0x48, 0x88, 0xB6, 0xF8, 0x4A, 0x30, 0x89, 0x46, 0xC0, 0x1A, 0xB6, 0xF8, + 0x46, 0x40, 0x92, 0x46, + 0x01, 0xB2, 0xB9, 0xF8, 0x00, 0x00, 0xB6, 0xF8, 0x48, 0x20, 0xE3, 0x1A, + 0x1C, 0xB2, 0x80, 0x1A, + 0xB6, 0xF8, 0x44, 0x30, 0x00, 0xB2, 0x9A, 0x1A, 0x15, 0xB2, 0x0C, 0xB9, + 0x00, 0x2D, 0x27, 0xD0, + 0x49, 0x43, 0x00, 0xFB, 0x00, 0x10, 0x64, 0x21, 0x48, 0x43, 0x04, 0xFB, + 0x04, 0xF1, 0x05, 0xFB, + 0x05, 0x11, 0xB0, 0xFB, 0xF1, 0xF0, 0x08, 0xF0, 0xC7, 0xFB, 0x44, 0x43, + 0x0A, 0x22, 0x45, 0x43, + 0x21, 0xB2, 0x28, 0xB2, 0x91, 0xFB, 0xF2, 0xF1, 0x90, 0xFB, 0xF2, 0xF0, + 0xB6, 0xF8, 0x46, 0x20, + 0x61, 0xF3, 0x1F, 0x48, 0x11, 0x44, 0x61, 0xF3, 0x1F, 0x47, 0xB6, 0xF8, + 0x44, 0x10, 0x60, 0xF3, + 0x0F, 0x08, 0x08, 0x44, 0x60, 0xF3, 0x0F, 0x07, 0xC9, 0xF8, 0x00, 0x70, + 0xCA, 0xF8, 0x00, 0x80, + 0xBD, 0xE8, 0xF0, 0x87, 0xB0, 0x05, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0xF0, 0xB5, 0x4F, 0xF0, + 0x00, 0x0C, 0x63, 0x46, 0x65, 0x46, 0x14, 0x46, 0x07, 0xE0, 0x00, 0xBF, + 0x01, 0xEB, 0xC4, 0x06, + 0x76, 0x68, 0x35, 0x44, 0x51, 0xF8, 0x34, 0x60, 0x33, 0x44, 0x64, 0x1E, + 0xF6, 0xD2, 0x95, 0xFB, + 0xF2, 0xF6, 0x93, 0xFB, 0xF2, 0xF7, 0xC0, 0xF8, 0x04, 0xC0, 0x15, 0x46, + 0x42, 0xF2, 0x10, 0x74, + 0xC0, 0xF8, 0x00, 0xC0, 0x17, 0xE0, 0x00, 0xBF, 0x01, 0xEB, 0xC5, 0x03, + 0x5B, 0x68, 0x9B, 0x1B, + 0x5B, 0x43, 0xA3, 0x42, 0x00, 0xDD, 0x23, 0x46, 0xD0, 0xF8, 0x04, 0xC0, + 0x63, 0x44, 0x43, 0x60, + 0x51, 0xF8, 0x35, 0x30, 0xDB, 0x1B, 0x5B, 0x43, 0xA3, 0x42, 0x00, 0xDD, + 0x23, 0x46, 0xD0, 0xF8, + 0x00, 0xC0, 0x63, 0x44, 0x03, 0x60, 0x6D, 0x1E, 0xE6, 0xD2, 0x41, 0x68, + 0x64, 0x23, 0x59, 0x43, + 0x91, 0xFB, 0xF2, 0xF1, 0x41, 0x60, 0x01, 0x68, 0x59, 0x43, 0x91, 0xFB, + 0xF2, 0xF1, 0x01, 0x60, + 0xF0, 0xBD, 0x00, 0x00, 0x10, 0xB5, 0x14, 0x21, 0x4B, 0x48, 0x0C, 0xF0, + 0x6F, 0xFB, 0xF6, 0xF7, + 0xD3, 0xFE, 0x64, 0x21, 0x48, 0x43, 0x48, 0x49, 0x08, 0x60, 0x10, 0xBD, + 0x2D, 0xE9, 0xF0, 0x41, + 0xDF, 0xF8, 0x18, 0x81, 0x04, 0x46, 0x0D, 0x46, 0xD8, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0xA0, 0x13, + 0x90, 0xF8, 0x80, 0x03, 0x01, 0xF0, 0x0F, 0x06, 0xC6, 0xF1, 0x10, 0x07, + 0x80, 0x07, 0x0F, 0xD5, + 0xB4, 0xF8, 0x42, 0x00, 0x01, 0x07, 0x0B, 0xD4, 0x00, 0x06, 0x09, 0xD4, + 0x0C, 0xF0, 0xFC, 0xFB, + 0x30, 0xB9, 0x3B, 0x48, 0x00, 0x78, 0x18, 0xB9, 0x3A, 0x48, 0x00, 0x78, + 0x01, 0x28, 0x02, 0xD9, + 0x00, 0x20, 0x20, 0x63, 0x18, 0xE0, 0x20, 0x6B, 0x02, 0x28, 0x18, 0xD8, + 0x40, 0x1C, 0x20, 0x63, + 0x02, 0x28, 0x07, 0xD9, 0x94, 0xF8, 0x3E, 0x11, 0x04, 0x29, 0x10, 0xD0, + 0x06, 0x29, 0x0E, 0xD0, + 0x07, 0x29, 0x0C, 0xD0, 0x02, 0x28, 0x07, 0xD1, 0xE0, 0x89, 0x61, 0x8A, + 0x40, 0x1A, 0x60, 0x85, + 0xA0, 0x89, 0x21, 0x8A, 0x40, 0x1A, 0x20, 0x85, 0x00, 0x20, 0xBD, 0xE8, + 0xF0, 0x81, 0xE0, 0x89, + 0x61, 0x8A, 0x22, 0x8A, 0x40, 0x1A, 0x01, 0xB2, 0xA0, 0x89, 0x79, 0x43, + 0x80, 0x1A, 0xB4, 0xF9, + 0x2A, 0x20, 0x00, 0xB2, 0x02, 0xFB, 0x06, 0x11, 0x09, 0x11, 0x61, 0x85, + 0xB4, 0xF9, 0x28, 0x10, + 0x78, 0x43, 0x01, 0xFB, 0x06, 0x00, 0x00, 0x11, 0x20, 0x85, 0xF6, 0xF7, + 0x2B, 0xFE, 0x1A, 0x4A, + 0x91, 0x89, 0x08, 0x1A, 0x11, 0x7C, 0x01, 0x29, 0x01, 0xD1, 0x51, 0x68, + 0x08, 0x44, 0x00, 0x28, + 0x00, 0xDA, 0x00, 0x20, 0x00, 0xEB, 0x80, 0x01, 0x13, 0x68, 0x49, 0x00, + 0xB1, 0xFB, 0xF3, 0xF7, + 0xD8, 0xF8, 0x00, 0x60, 0xB6, 0xF8, 0xA1, 0x13, 0x8F, 0x42, 0x03, 0xD9, + 0x59, 0x43, 0x0A, 0x20, + 0xB1, 0xFB, 0xF0, 0xF0, 0xB4, 0xF9, 0x2A, 0x10, 0x96, 0xF8, 0xA3, 0x33, + 0x92, 0x68, 0x59, 0x43, + 0x64, 0x26, 0x41, 0x43, 0x72, 0x43, 0xB4, 0xF9, 0x28, 0x40, 0x91, 0xFB, + 0xF2, 0xF1, 0x5C, 0x43, + 0x44, 0x43, 0x94, 0xFB, 0xF2, 0xF0, 0x6A, 0x88, 0x11, 0x44, 0x69, 0x80, + 0x29, 0x88, 0x08, 0x44, + 0x28, 0x80, 0x01, 0x20, 0xB1, 0xE7, 0x00, 0x00, 0x6C, 0x2C, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0x74, 0x05, 0x10, 0x00, 0x20, 0x07, 0x10, 0x00, 0xB0, 0xF8, 0x44, 0x20, + 0xB1, 0xF8, 0x44, 0x30, + 0x1A, 0x44, 0xA0, 0xF8, 0x44, 0x20, 0xB0, 0xF8, 0x46, 0x20, 0xB1, 0xF8, + 0x46, 0x30, 0x1A, 0x44, + 0xA0, 0xF8, 0x46, 0x20, 0x42, 0x6B, 0x4B, 0x6B, 0x1A, 0x44, 0x42, 0x63, + 0x82, 0x6B, 0x8B, 0x6B, + 0x1A, 0x44, 0x82, 0x63, 0xB1, 0xF9, 0x54, 0x20, 0xB0, 0xF9, 0x54, 0x30, + 0x9A, 0x42, 0x01, 0xDD, + 0xA0, 0xF8, 0x54, 0x20, 0xB1, 0xF9, 0x56, 0x20, 0xB0, 0xF9, 0x56, 0x30, + 0x9A, 0x42, 0x01, 0xDD, + 0xA0, 0xF8, 0x56, 0x20, 0x90, 0xF8, 0x46, 0x21, 0x91, 0xF8, 0x46, 0x31, + 0x9A, 0x42, 0x0A, 0xD0, + 0x30, 0xF8, 0x48, 0x2F, 0xB1, 0xF8, 0x48, 0x30, 0x1A, 0x44, 0x20, 0xF8, + 0x0C, 0x29, 0xC9, 0x6B, + 0x02, 0x68, 0x11, 0x44, 0x01, 0x60, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x4F, + 0x97, 0xB0, 0x80, 0x46, + 0x00, 0xF5, 0x80, 0x50, 0x00, 0x26, 0x11, 0x90, 0xBF, 0xE0, 0x00, 0x20, + 0x08, 0x90, 0x05, 0x90, + 0x10, 0x90, 0x12, 0x90, 0x81, 0x46, 0x82, 0x46, 0x83, 0x46, 0x05, 0x46, + 0x07, 0x46, 0x0A, 0x90, + 0x0B, 0x90, 0x0C, 0x90, 0x0D, 0x90, 0x08, 0xEB, 0x86, 0x00, 0x00, 0xF5, + 0x80, 0x50, 0x14, 0x90, + 0xD0, 0xF8, 0x68, 0x04, 0x0A, 0xAA, 0x04, 0x46, 0x17, 0xE0, 0x00, 0xBF, + 0x90, 0xF8, 0x46, 0x11, + 0x08, 0xEB, 0x01, 0x0C, 0x53, 0x5C, 0x0C, 0xF5, 0x80, 0x5C, 0x5B, 0x1C, + 0xDB, 0xB2, 0x53, 0x54, + 0x9C, 0xF8, 0x56, 0xC4, 0x63, 0x45, 0x06, 0xD1, 0x01, 0x2B, 0x04, 0xD9, + 0x01, 0x23, 0x8B, 0x40, + 0x12, 0x99, 0x0B, 0x43, 0x12, 0x93, 0xD0, 0xF8, 0x50, 0x01, 0x00, 0x28, + 0xE6, 0xD1, 0x40, 0xE0, + 0x94, 0xF8, 0x46, 0x11, 0x01, 0x20, 0x00, 0xFA, 0x01, 0xFC, 0x12, 0x99, + 0x1C, 0xEA, 0x01, 0x0F, + 0x12, 0xD1, 0xA0, 0x6B, 0xB4, 0xF9, 0x0E, 0x30, 0x05, 0x9A, 0x49, 0x46, + 0xC0, 0xFB, 0x03, 0x12, + 0x05, 0x92, 0x89, 0x46, 0xB4, 0xF9, 0x0C, 0x30, 0x51, 0x46, 0x5A, 0x46, + 0xC0, 0xFB, 0x03, 0x12, + 0x8A, 0x46, 0x93, 0x46, 0x05, 0x44, 0x19, 0xE0, 0x08, 0x99, 0x1C, 0xEA, + 0x01, 0x0F, 0x15, 0xD1, + 0xE0, 0x6B, 0xB4, 0xF9, 0x1E, 0x30, 0x05, 0x9A, 0x49, 0x46, 0xC0, 0xFB, + 0x03, 0x12, 0x05, 0x92, + 0x89, 0x46, 0xB4, 0xF9, 0x1C, 0x30, 0x51, 0x46, 0x5A, 0x46, 0xC0, 0xFB, + 0x03, 0x12, 0x8A, 0x46, + 0x08, 0x99, 0x05, 0x44, 0x4C, 0xEA, 0x01, 0x00, 0x93, 0x46, 0x08, 0x90, + 0x20, 0x46, 0x00, 0xF0, + 0x98, 0xFB, 0x01, 0x28, 0x02, 0xD1, 0x10, 0x98, 0x40, 0x1C, 0x10, 0x90, + 0xD4, 0xF8, 0x50, 0x41, + 0x7F, 0x1C, 0x00, 0x2C, 0xBC, 0xD1, 0x00, 0x2F, 0x45, 0xDD, 0xE8, 0x17, + 0x04, 0x46, 0x03, 0x46, + 0x2A, 0x46, 0x48, 0x46, 0x05, 0x99, 0x0C, 0xF0, 0x4C, 0xF9, 0xAD, 0xF8, + 0x1E, 0x00, 0x2A, 0x46, + 0x23, 0x46, 0x50, 0x46, 0x59, 0x46, 0x0C, 0xF0, 0x44, 0xF9, 0xAD, 0xF8, + 0x1C, 0x00, 0x14, 0x98, + 0x4F, 0xF0, 0xFF, 0x37, 0x00, 0x25, 0xD0, 0xF8, 0x68, 0x44, 0x23, 0xE0, + 0x20, 0x46, 0x00, 0xF0, + 0x70, 0xFB, 0x01, 0x28, 0x01, 0xD0, 0x10, 0x98, 0x90, 0xB9, 0x04, 0xF1, + 0x10, 0x01, 0x07, 0xA8, + 0x08, 0xF0, 0xB9, 0xFA, 0xB8, 0x42, 0x0B, 0xD2, 0x07, 0x46, 0x3D, 0xB1, + 0x29, 0x46, 0x20, 0x46, + 0xFF, 0xF7, 0x1A, 0xFF, 0x29, 0x46, 0x40, 0x46, 0x00, 0xF0, 0x72, 0xFB, + 0x25, 0x46, 0x07, 0xE0, + 0x21, 0x46, 0x28, 0x46, 0xFF, 0xF7, 0x10, 0xFF, 0x21, 0x46, 0x40, 0x46, + 0x00, 0xF0, 0x68, 0xFB, + 0xD4, 0xF8, 0x50, 0x41, 0x00, 0x2C, 0xD9, 0xD1, 0x07, 0x98, 0x45, 0xF8, + 0x0C, 0x0F, 0xE8, 0x8E, + 0x40, 0xF0, 0x40, 0x00, 0xE8, 0x86, 0x11, 0x98, 0x76, 0x1C, 0x90, 0xF8, + 0xE0, 0x04, 0xB0, 0x42, + 0x3F, 0xF7, 0x3B, 0xAF, 0x17, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, + 0xF7, 0x4F, 0x05, 0x46, + 0x0E, 0x46, 0x01, 0xEB, 0x06, 0x10, 0x00, 0xEB, 0x80, 0x00, 0x82, 0xB0, + 0x05, 0xEB, 0x80, 0x0A, + 0x00, 0x24, 0x4F, 0xF0, 0x01, 0x08, 0xDF, 0xF8, 0x98, 0xB5, 0x05, 0xF5, + 0x80, 0x57, 0x7F, 0xE0, + 0xD7, 0xF8, 0xEC, 0x23, 0x08, 0xFA, 0x04, 0xF9, 0x12, 0xEA, 0x09, 0x0F, + 0x77, 0xD0, 0xB4, 0x42, + 0x75, 0xD0, 0xDB, 0xF8, 0x08, 0x10, 0x31, 0xF8, 0x16, 0x10, 0x11, 0xEA, + 0x09, 0x0F, 0x6E, 0xD1, + 0x04, 0xEB, 0x04, 0x10, 0x00, 0xEB, 0x80, 0x00, 0x05, 0xEB, 0x80, 0x00, + 0x00, 0x90, 0x00, 0xF0, + 0x0A, 0xFB, 0x01, 0x28, 0x04, 0xD0, 0x00, 0x98, 0x00, 0xF0, 0x0B, 0xFB, + 0x01, 0x28, 0x5E, 0xD1, + 0x00, 0x98, 0x00, 0xF0, 0xF8, 0xFA, 0xE8, 0xBB, 0x00, 0x99, 0x0A, 0xF1, + 0x0C, 0x00, 0x0C, 0x31, + 0x08, 0xF0, 0x51, 0xFA, 0x01, 0x90, 0xDB, 0xF8, 0x08, 0x00, 0x08, 0xFA, + 0x06, 0xF2, 0x30, 0xF8, + 0x16, 0x30, 0x43, 0xEA, 0x09, 0x03, 0x20, 0xF8, 0x16, 0x30, 0x30, 0xF8, + 0x14, 0x30, 0x13, 0x43, + 0x20, 0xF8, 0x14, 0x30, 0x50, 0x46, 0xDB, 0xF8, 0x00, 0x90, 0x00, 0xF0, + 0xF6, 0xFA, 0x01, 0x28, + 0x04, 0xD1, 0x00, 0x98, 0x00, 0xF0, 0xDF, 0xFA, 0x01, 0x28, 0x1D, 0xD0, + 0x50, 0x46, 0x00, 0xF0, + 0xDA, 0xFA, 0x01, 0x28, 0x04, 0xD1, 0x00, 0x98, 0x00, 0xF0, 0xE7, 0xFA, + 0x01, 0x28, 0x13, 0xD0, + 0x50, 0x46, 0x00, 0xF0, 0xD0, 0xFA, 0x01, 0x28, 0x1E, 0xD1, 0x00, 0x98, + 0x00, 0xF0, 0xCB, 0xFA, + 0x01, 0x28, 0x19, 0xD1, 0x00, 0x99, 0x9A, 0xF8, 0x42, 0x00, 0x91, 0xF8, + 0x42, 0x10, 0x08, 0x43, + 0x80, 0x06, 0x00, 0xE0, 0x1B, 0xE0, 0x0F, 0xD5, 0xBA, 0xF8, 0x42, 0x00, + 0xDB, 0xF8, 0x04, 0x90, + 0x40, 0xF0, 0x20, 0x01, 0xAA, 0xF8, 0x42, 0x10, 0x00, 0x98, 0xB0, 0xF8, + 0x42, 0x00, 0x40, 0xF0, + 0x20, 0x01, 0x00, 0x98, 0xA0, 0xF8, 0x42, 0x10, 0x01, 0x98, 0x48, 0x45, + 0x07, 0xD2, 0x41, 0xF2, + 0x68, 0x40, 0x51, 0x46, 0x28, 0x44, 0x04, 0x9B, 0x00, 0x9A, 0x00, 0xF0, + 0xD0, 0xFA, 0x64, 0x1C, + 0x97, 0xF9, 0xF4, 0x03, 0xA0, 0x42, 0xBF, 0xF6, 0x7B, 0xAF, 0x05, 0xB0, + 0x63, 0xE7, 0x2D, 0xE9, + 0xF8, 0x4F, 0x88, 0x46, 0x06, 0x46, 0x01, 0xEB, 0x08, 0x10, 0x00, 0xEB, + 0x80, 0x00, 0x06, 0xEB, + 0x80, 0x04, 0xDF, 0xF8, 0x6C, 0xA4, 0x94, 0xF8, 0x42, 0x00, 0x4F, 0xF0, + 0x04, 0x0B, 0x40, 0x06, + 0x4F, 0xF0, 0x01, 0x09, 0x06, 0xF5, 0x80, 0x55, 0x2E, 0xD5, 0x00, 0x27, + 0x04, 0xF1, 0x0C, 0x0B, + 0x24, 0xE0, 0x00, 0xBF, 0xD5, 0xF8, 0xEC, 0x13, 0x09, 0xFA, 0x07, 0xF0, + 0x01, 0x42, 0x1C, 0xD0, + 0x47, 0x45, 0x1A, 0xD0, 0x07, 0xEB, 0x07, 0x10, 0x00, 0xEB, 0x80, 0x00, + 0x06, 0xEB, 0x80, 0x00, + 0x00, 0x90, 0x00, 0xF0, 0x70, 0xFA, 0x01, 0x28, 0x0F, 0xD1, 0x00, 0x98, + 0x00, 0xF0, 0x63, 0xFA, + 0x58, 0xB9, 0x00, 0x99, 0x58, 0x46, 0x10, 0x31, 0x08, 0xF0, 0xBD, 0xF9, + 0xDA, 0xF8, 0x04, 0x10, + 0x88, 0x42, 0x02, 0xD2, 0x04, 0x20, 0x84, 0xF8, 0x3E, 0x01, 0x7F, 0x1C, + 0x95, 0xF9, 0xF4, 0x03, + 0xB8, 0x42, 0xD7, 0xDA, 0xBD, 0xE8, 0xF8, 0x8F, 0xFE, 0x48, 0xE1, 0x6A, + 0x00, 0x68, 0x90, 0xF8, + 0x95, 0x03, 0x81, 0x42, 0xF6, 0xD9, 0x00, 0x27, 0x31, 0xE0, 0x00, 0xBF, + 0xD5, 0xF8, 0xEC, 0x13, + 0x09, 0xFA, 0x07, 0xF0, 0x01, 0x42, 0x29, 0xD0, 0x47, 0x45, 0x27, 0xD0, + 0x07, 0xEB, 0x07, 0x10, + 0x00, 0xEB, 0x80, 0x00, 0x06, 0xEB, 0x80, 0x00, 0x00, 0x90, 0x00, 0xF0, + 0x3C, 0xFA, 0x01, 0x28, + 0x1C, 0xD1, 0x00, 0x98, 0x94, 0xF8, 0x46, 0x11, 0x90, 0xF8, 0x47, 0x01, + 0x81, 0x42, 0x15, 0xD1, + 0x00, 0x98, 0x00, 0xF0, 0x28, 0xFA, 0x88, 0xB9, 0x00, 0x99, 0x04, 0xF1, + 0x0C, 0x00, 0x10, 0x31, + 0x08, 0xF0, 0x81, 0xF9, 0xDA, 0xF8, 0x04, 0x10, 0x88, 0x42, 0x07, 0xD2, + 0x84, 0xF8, 0x3E, 0xB1, + 0xB4, 0xF8, 0x42, 0x00, 0x40, 0xF0, 0x40, 0x00, 0xA4, 0xF8, 0x42, 0x00, + 0x7F, 0x1C, 0x95, 0xF9, + 0xF4, 0x03, 0xB8, 0x42, 0xCA, 0xDA, 0x00, 0x27, 0x0C, 0x34, 0x26, 0xE0, + 0xD5, 0xF8, 0xEC, 0x13, + 0x09, 0xFA, 0x07, 0xF0, 0x01, 0x42, 0x1F, 0xD0, 0x47, 0x45, 0x1D, 0xD0, + 0x07, 0xEB, 0x07, 0x10, + 0x00, 0xEB, 0x80, 0x00, 0x06, 0xEB, 0x80, 0x00, 0x83, 0x46, 0x00, 0xF0, + 0x0A, 0xFA, 0x01, 0x28, + 0x12, 0xD1, 0x58, 0x46, 0x00, 0xF0, 0xF7, 0xF9, 0x70, 0xB9, 0x0B, 0xF1, + 0x10, 0x01, 0x20, 0x46, + 0x08, 0xF0, 0x51, 0xF9, 0xDA, 0xF8, 0x04, 0x10, 0x88, 0x42, 0x05, 0xD2, + 0xBB, 0xF8, 0x42, 0x00, + 0x40, 0xF0, 0x40, 0x01, 0xAB, 0xF8, 0x42, 0x10, 0x7F, 0x1C, 0x95, 0xF9, + 0xF4, 0x03, 0xB8, 0x42, + 0xD4, 0xDA, 0x8F, 0xE7, 0x2D, 0xE9, 0xF8, 0x43, 0x06, 0x46, 0xFF, 0x20, + 0x00, 0x25, 0x8D, 0xF8, + 0x00, 0x00, 0x01, 0x27, 0x06, 0xF5, 0x80, 0x54, 0x1A, 0xE0, 0x00, 0xBF, + 0x05, 0xEB, 0x05, 0x10, + 0x00, 0xEB, 0x80, 0x00, 0x06, 0xEB, 0x80, 0x08, 0xD4, 0xF8, 0xEC, 0x03, + 0x07, 0xFA, 0x05, 0xF1, + 0x08, 0x42, 0x0C, 0xD0, 0x40, 0x46, 0x00, 0xF0, 0xC6, 0xF9, 0x01, 0x28, + 0x07, 0xD0, 0x98, 0xF8, + 0x3E, 0x01, 0x05, 0x28, 0x03, 0xD1, 0x29, 0x46, 0x30, 0x46, 0xFF, 0xF7, + 0x28, 0xFF, 0x6D, 0x1C, + 0x94, 0xF9, 0xF4, 0x03, 0xA8, 0x42, 0xE1, 0xDA, 0x00, 0x25, 0x1B, 0xE0, + 0x05, 0xEB, 0x05, 0x10, + 0x00, 0xEB, 0x80, 0x00, 0x06, 0xEB, 0x80, 0x08, 0xD4, 0xF8, 0xEC, 0x03, + 0x07, 0xFA, 0x05, 0xF1, + 0x08, 0x42, 0x0E, 0xD0, 0x40, 0x46, 0x00, 0xF0, 0xA6, 0xF9, 0x01, 0x28, + 0x09, 0xD0, 0x40, 0x46, + 0x00, 0xF0, 0xAF, 0xF9, 0x01, 0x28, 0x04, 0xD1, 0x6A, 0x46, 0x29, 0x46, + 0x30, 0x46, 0xFF, 0xF7, + 0x6C, 0xFE, 0x6D, 0x1C, 0x94, 0xF9, 0xF4, 0x03, 0xA8, 0x42, 0xDF, 0xDA, + 0x00, 0x25, 0xB8, 0x46, + 0x21, 0xE0, 0x00, 0xBF, 0x05, 0xEB, 0x05, 0x10, 0x00, 0xEB, 0x80, 0x00, + 0x06, 0xEB, 0x80, 0x07, + 0xD4, 0xF8, 0xEC, 0x13, 0x08, 0xFA, 0x05, 0xF0, 0x01, 0x42, 0x13, 0xD0, + 0x38, 0x46, 0x00, 0xF0, + 0x82, 0xF9, 0x01, 0x28, 0x0E, 0xD0, 0x38, 0x46, 0x00, 0xF0, 0x85, 0xF9, + 0x01, 0x28, 0x04, 0xD1, + 0x6A, 0x46, 0x29, 0x46, 0x30, 0x46, 0xFF, 0xF7, 0x48, 0xFE, 0x37, 0xF8, + 0x42, 0x0F, 0x20, 0xF0, + 0x20, 0x00, 0x38, 0x80, 0x6D, 0x1C, 0x94, 0xF9, 0xF4, 0x03, 0xA8, 0x42, + 0xDA, 0xDA, 0x9D, 0xF8, + 0x00, 0x00, 0x40, 0x1C, 0x84, 0xF8, 0xE0, 0x04, 0xBD, 0xE8, 0xF8, 0x83, + 0x10, 0xB5, 0x04, 0x46, + 0x87, 0x48, 0x03, 0x21, 0x08, 0x30, 0x05, 0xF0, 0xD2, 0xFB, 0x85, 0x48, + 0x1E, 0x21, 0x80, 0x68, + 0x0B, 0xF0, 0xD2, 0xFF, 0x41, 0xF2, 0x68, 0x40, 0x7C, 0x21, 0x20, 0x44, + 0x0B, 0xF0, 0xEE, 0xFF, + 0x80, 0x48, 0x02, 0x68, 0x80, 0x48, 0xB2, 0xF8, 0x96, 0x13, 0x00, 0x78, + 0x49, 0x43, 0x10, 0xB1, + 0xB2, 0xF8, 0x6C, 0x13, 0x49, 0x43, 0xB2, 0xF8, 0x98, 0x23, 0x02, 0xFB, + 0x02, 0x10, 0x78, 0x4A, + 0x11, 0x60, 0x11, 0x1D, 0x08, 0x60, 0x20, 0x46, 0xFF, 0xF7, 0x5C, 0xFF, + 0x20, 0x46, 0xFF, 0xF7, + 0x3B, 0xFD, 0x73, 0x48, 0x03, 0x21, 0xBD, 0xE8, 0x10, 0x40, 0x08, 0x30, + 0x05, 0xF0, 0xC4, 0xBB, + 0xF0, 0xB4, 0x84, 0x6B, 0xC2, 0x68, 0x8B, 0x6B, 0xCE, 0x68, 0x17, 0x14, + 0x67, 0x43, 0x4F, 0xEA, + 0x26, 0x4C, 0x03, 0xFB, 0x0C, 0x77, 0xE5, 0x18, 0x97, 0xFB, 0xF5, 0xF7, + 0x67, 0xF3, 0x1F, 0x42, + 0x17, 0xB2, 0x67, 0x43, 0x34, 0xB2, 0x03, 0xFB, 0x04, 0x73, 0x93, 0xFB, + 0xF5, 0xF3, 0x63, 0xF3, + 0x0F, 0x02, 0xC2, 0x60, 0xF0, 0xBC, 0xDF, 0xE4, 0x62, 0x4A, 0x12, 0x68, + 0x92, 0xF8, 0x40, 0x24, + 0x92, 0x06, 0x11, 0xD5, 0x90, 0xF8, 0x49, 0x31, 0x23, 0xB1, 0x91, 0xF8, + 0x49, 0x21, 0x0A, 0xB1, + 0x93, 0x42, 0x07, 0xD1, 0x90, 0xF8, 0x4A, 0x01, 0x30, 0xB1, 0x91, 0xF8, + 0x4A, 0x11, 0x19, 0xB1, + 0x88, 0x42, 0x01, 0xD0, 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, + 0x2D, 0xE9, 0xFE, 0x4F, + 0x00, 0xF5, 0x80, 0x54, 0x05, 0x46, 0xD4, 0xF8, 0xF8, 0x13, 0xD4, 0xF8, + 0xEC, 0x03, 0x01, 0x40, + 0x00, 0x28, 0xC4, 0xF8, 0xF8, 0x13, 0x4F, 0xF0, 0x00, 0x00, 0x0C, 0xD0, + 0x81, 0x46, 0x0F, 0x21, + 0x4E, 0x48, 0x0B, 0xF0, 0x61, 0xFF, 0x00, 0x26, 0xDF, 0xF8, 0x30, 0xA1, + 0x4F, 0xF0, 0x01, 0x08, + 0x41, 0xF2, 0xFC, 0x3B, 0x5A, 0xE0, 0xC4, 0xF8, 0xF8, 0x03, 0xBD, 0xE8, + 0xFE, 0x8F, 0xD4, 0xF8, + 0xEC, 0x23, 0x08, 0xFA, 0x06, 0xF1, 0x40, 0x46, 0x0A, 0x42, 0x4E, 0xD0, + 0x06, 0xEB, 0x06, 0x12, + 0x02, 0xEB, 0x82, 0x02, 0x05, 0xEB, 0x82, 0x07, 0x97, 0xF8, 0x40, 0x20, + 0x12, 0x06, 0xD4, 0xF8, + 0xF8, 0x23, 0x11, 0xD5, 0x0A, 0x43, 0x05, 0xEB, 0x86, 0x01, 0xC4, 0xF8, + 0xF8, 0x23, 0x01, 0xF5, + 0x9C, 0x51, 0xD7, 0xF8, 0x5A, 0x20, 0xCA, 0x67, 0x97, 0xF8, 0x46, 0x11, + 0x88, 0x40, 0x40, 0xEA, + 0x09, 0x09, 0x0A, 0xF8, 0x01, 0x60, 0x30, 0xE0, 0x0A, 0x42, 0x2E, 0xD0, + 0x97, 0xF8, 0x3E, 0x21, + 0x06, 0x2A, 0x14, 0xD0, 0x05, 0x2A, 0x12, 0xD0, 0x97, 0xF8, 0x46, 0x11, + 0x08, 0xFA, 0x01, 0xF0, + 0x40, 0xEA, 0x09, 0x09, 0x0A, 0xF8, 0x01, 0x60, 0x05, 0xEB, 0x86, 0x01, + 0x01, 0xEB, 0x0B, 0x00, + 0x5A, 0x37, 0x39, 0x46, 0x00, 0x90, 0x03, 0xF0, 0x8F, 0xFB, 0x98, 0xB1, + 0x15, 0xE0, 0xB7, 0xF8, + 0x42, 0x00, 0x20, 0xF0, 0x08, 0x00, 0xA7, 0xF8, 0x42, 0x00, 0xD4, 0xF8, + 0xF8, 0x03, 0x88, 0x43, + 0xC4, 0xF8, 0xF8, 0x03, 0x22, 0x49, 0x05, 0xEB, 0x86, 0x00, 0x00, 0xF5, + 0x9C, 0x50, 0x09, 0x68, + 0xC1, 0x67, 0xE1, 0xE7, 0x00, 0x98, 0x39, 0x68, 0x01, 0x60, 0x76, 0x1C, + 0x94, 0xF9, 0xF4, 0x03, + 0xB0, 0x42, 0xA4, 0xDA, 0x00, 0x27, 0x72, 0xE0, 0xD4, 0xF8, 0xEC, 0x23, + 0x08, 0xFA, 0x07, 0xF1, + 0x0A, 0x42, 0x6B, 0xD0, 0xD4, 0xF8, 0xF8, 0x23, 0x0A, 0x42, 0x67, 0xD1, + 0x07, 0xEB, 0x07, 0x11, + 0x01, 0xEB, 0x81, 0x01, 0x05, 0xEB, 0x81, 0x01, 0x00, 0x91, 0x91, 0xF8, + 0x3E, 0x11, 0x02, 0x29, + 0x01, 0xD0, 0x01, 0x29, 0x5A, 0xD1, 0x00, 0x99, 0x43, 0x46, 0x91, 0xF8, + 0x46, 0x11, 0x08, 0xFA, + 0x01, 0xF0, 0x10, 0xEA, 0x09, 0x0F, 0x23, 0xD0, 0x1A, 0xF8, 0x01, 0x00, + 0xB8, 0x42, 0x4D, 0xD0, + 0x00, 0xEB, 0x00, 0x10, 0x00, 0xEB, 0x80, 0x00, 0x05, 0xEB, 0x80, 0x00, + 0x06, 0x46, 0x09, 0xE0, + 0x08, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xFD, 0x06, 0x10, 0x00, + 0x80, 0x2C, 0x10, 0x00, + 0x36, 0x7A, 0x01, 0x00, 0x00, 0x99, 0xFF, 0xF7, 0x2F, 0xFF, 0x01, 0x28, + 0x36, 0xD1, 0x30, 0x46, + 0x00, 0x99, 0xFF, 0xF7, 0x0D, 0xFF, 0x28, 0x46, 0x00, 0x99, 0x00, 0xF0, + 0xF7, 0xFD, 0x2D, 0xE0, + 0x00, 0x98, 0x98, 0x46, 0x5A, 0x30, 0x00, 0x26, 0x02, 0x90, 0x23, 0xE0, + 0xD4, 0xF8, 0xF8, 0x13, + 0x08, 0xFA, 0x06, 0xF0, 0x01, 0x42, 0x1C, 0xD0, 0x06, 0xEB, 0x06, 0x10, + 0x00, 0xEB, 0x80, 0x00, + 0x05, 0xEB, 0x80, 0x00, 0x05, 0xEB, 0x86, 0x01, 0x01, 0x90, 0x59, 0x44, + 0x02, 0x98, 0x03, 0xF0, + 0x13, 0xFB, 0x01, 0x28, 0x0D, 0xD1, 0xDD, 0xE9, 0x00, 0x10, 0xFF, 0xF7, + 0x05, 0xFF, 0x01, 0x28, + 0x07, 0xD1, 0xDD, 0xE9, 0x00, 0x10, 0xFF, 0xF7, 0xE3, 0xFE, 0x28, 0x46, + 0x00, 0x99, 0x00, 0xF0, + 0xCD, 0xFD, 0x76, 0x1C, 0x94, 0xF9, 0xF4, 0x03, 0xB0, 0x42, 0xD7, 0xDA, + 0x7F, 0x1C, 0x94, 0xF9, + 0xF4, 0x03, 0xB8, 0x42, 0x88, 0xDA, 0x28, 0xE7, 0x33, 0x49, 0x00, 0x20, + 0x88, 0x60, 0x0F, 0x21, + 0x32, 0x48, 0x0B, 0xF0, 0x79, 0xBE, 0x90, 0xF8, 0x42, 0x00, 0x40, 0x07, + 0x01, 0xD5, 0x01, 0x20, + 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x90, 0xF8, 0x3E, 0x01, 0x01, 0x28, + 0x00, 0xD0, 0x00, 0x20, + 0x70, 0x47, 0x90, 0xF8, 0x3E, 0x01, 0x02, 0x28, 0x05, 0xD0, 0x03, 0x28, + 0x03, 0xD0, 0x04, 0x28, + 0x01, 0xD0, 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, 0x10, 0xB5, + 0x90, 0xF8, 0x42, 0x10, + 0x49, 0x06, 0x03, 0xD5, 0xFF, 0xF7, 0xED, 0xFF, 0x01, 0x28, 0x00, 0xD0, + 0x00, 0x20, 0x10, 0xBD, + 0x91, 0xF8, 0x3E, 0x21, 0x01, 0x2A, 0x08, 0xD0, 0x02, 0x2A, 0x06, 0xD0, + 0x06, 0x20, 0x81, 0xF8, + 0x3E, 0x01, 0x00, 0x20, 0x81, 0xF8, 0x43, 0x01, 0x70, 0x47, 0x00, 0xF0, + 0x87, 0xBD, 0xF0, 0xB5, + 0x91, 0xF9, 0x4B, 0x61, 0x93, 0xF9, 0x00, 0x40, 0x92, 0xF9, 0x4B, 0x51, + 0x77, 0x1C, 0x02, 0xD0, + 0x6D, 0x1C, 0x15, 0xD0, 0x0B, 0xE0, 0x6E, 0x1C, 0x0B, 0xD0, 0x00, 0xEB, + 0x85, 0x02, 0x00, 0xEB, + 0x84, 0x00, 0xD2, 0x6B, 0xC2, 0xF8, 0x50, 0x11, 0xC1, 0x63, 0x81, 0xF8, + 0x4B, 0x41, 0x1C, 0x70, + 0xF0, 0xBD, 0x64, 0x1C, 0x64, 0xB2, 0x40, 0xF8, 0x24, 0x10, 0x81, 0xF8, + 0x4B, 0x41, 0x02, 0xE0, + 0x00, 0xEB, 0x86, 0x01, 0xC9, 0x6B, 0x00, 0xEB, 0x84, 0x00, 0xC1, 0xF8, + 0x50, 0x21, 0xC2, 0x63, + 0x82, 0xF8, 0x4B, 0x41, 0xEB, 0xE7, 0x00, 0x00, 0x08, 0x06, 0x10, 0x00, + 0x80, 0x2C, 0x10, 0x00, + 0xF0, 0xB5, 0x44, 0x88, 0x4E, 0x88, 0x01, 0x25, 0xA4, 0x1B, 0x24, 0xB2, + 0x00, 0x2C, 0x01, 0xDB, + 0x26, 0x46, 0x00, 0xE0, 0x66, 0x42, 0x5E, 0x80, 0x56, 0x42, 0x94, 0x42, + 0x02, 0xDD, 0x44, 0x88, + 0xA4, 0x1A, 0x03, 0xE0, 0xB4, 0x42, 0x03, 0xDA, 0x44, 0x88, 0x14, 0x44, + 0x4C, 0x80, 0x00, 0x25, + 0x04, 0x88, 0x0F, 0x88, 0xE4, 0x1B, 0x24, 0xB2, 0x00, 0x2C, 0x01, 0xDB, + 0x27, 0x46, 0x00, 0xE0, + 0x67, 0x42, 0x1F, 0x80, 0x94, 0x42, 0x02, 0xDD, 0x00, 0x88, 0x80, 0x1A, + 0x03, 0xE0, 0xB4, 0x42, + 0x03, 0xDA, 0x00, 0x88, 0x10, 0x44, 0x08, 0x80, 0x00, 0x25, 0x28, 0x46, + 0xF0, 0xBD, 0x2D, 0xE9, + 0xF0, 0x41, 0x96, 0x4D, 0x0F, 0x46, 0x06, 0x46, 0x81, 0x89, 0x28, 0x68, + 0x90, 0x46, 0xF9, 0xB1, + 0x90, 0xF8, 0xC7, 0x43, 0x0B, 0xF0, 0xA8, 0xFE, 0x18, 0xB1, 0x28, 0x68, + 0x90, 0xF8, 0xC9, 0x43, + 0x12, 0xE0, 0xB0, 0x7D, 0x02, 0x28, 0x04, 0xD0, 0x01, 0x28, 0x06, 0xD0, + 0x03, 0x28, 0x08, 0xD0, + 0x0A, 0xE0, 0x28, 0x68, 0x90, 0xF8, 0xCE, 0x43, 0x06, 0xE0, 0x28, 0x68, + 0x90, 0xF8, 0x51, 0x44, + 0x02, 0xE0, 0x28, 0x68, 0x90, 0xF8, 0x2C, 0x44, 0xB0, 0x89, 0x40, 0x1E, + 0xB0, 0x81, 0x11, 0xE0, + 0xB1, 0x7D, 0x90, 0xF8, 0xCB, 0x43, 0x02, 0x29, 0x04, 0xD0, 0x01, 0x29, + 0x05, 0xD0, 0x03, 0x29, + 0x06, 0xD0, 0x07, 0xE0, 0x90, 0xF8, 0xCE, 0x43, 0x04, 0xE0, 0x90, 0xF8, + 0x52, 0x44, 0x01, 0xE0, + 0x90, 0xF8, 0x2D, 0x44, 0x29, 0x68, 0xB2, 0x7D, 0x91, 0xF8, 0xCA, 0x03, + 0x02, 0x2A, 0x04, 0xD0, + 0x01, 0x2A, 0x05, 0xD0, 0x03, 0x2A, 0x06, 0xD0, 0x07, 0xE0, 0x91, 0xF8, + 0xCD, 0x03, 0x04, 0xE0, + 0x91, 0xF8, 0x53, 0x04, 0x01, 0xE0, 0x91, 0xF8, 0x2E, 0x04, 0x38, 0x80, + 0xA8, 0xF8, 0x00, 0x40, + 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xF0, 0x4F, 0x00, 0xF1, 0x5E, 0x04, + 0x85, 0xB0, 0x4F, 0xF0, + 0x00, 0x0B, 0x84, 0xF8, 0x15, 0xB0, 0xDF, 0xF8, 0xA4, 0x91, 0x0E, 0x46, + 0x80, 0xF8, 0x74, 0xB0, + 0x05, 0x46, 0xB0, 0xF8, 0x42, 0x10, 0x4F, 0xF0, 0x01, 0x08, 0xD9, 0xF8, + 0x00, 0x00, 0x4A, 0x06, + 0xC2, 0x46, 0x01, 0xD5, 0x02, 0x21, 0x0F, 0xE0, 0x0A, 0x07, 0x06, 0xD5, + 0x90, 0xF8, 0x40, 0x24, + 0x52, 0x06, 0x02, 0xD5, 0x84, 0xF8, 0x16, 0xA0, 0x07, 0xE0, 0x90, 0xF8, + 0x20, 0x24, 0x92, 0x07, + 0x03, 0xD5, 0x09, 0x06, 0x01, 0xD5, 0x03, 0x21, 0xA1, 0x75, 0x95, 0xF8, + 0x3E, 0x11, 0x03, 0x29, + 0x09, 0xD0, 0xA2, 0x7C, 0x01, 0x2A, 0x06, 0xD0, 0x04, 0x29, 0x2D, 0xD0, + 0x07, 0x29, 0x2B, 0xD0, + 0x08, 0x29, 0x76, 0xD0, 0x9C, 0xE0, 0x90, 0xF8, 0xC6, 0x73, 0x0B, 0xF0, + 0x25, 0xFE, 0x18, 0xB1, + 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0xC8, 0x73, 0x95, 0xF8, 0x3E, 0x01, + 0x03, 0x28, 0x00, 0xD0, + 0x00, 0x27, 0xA0, 0x7D, 0x01, 0x28, 0x02, 0xD0, 0x03, 0x28, 0x05, 0xD0, + 0x08, 0xE0, 0xD9, 0xF8, + 0x00, 0x00, 0x90, 0xF8, 0x50, 0x74, 0x03, 0xE0, 0xD9, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0x2B, 0x74, + 0xA7, 0x81, 0x31, 0x68, 0x21, 0x60, 0x31, 0x68, 0x61, 0x60, 0x84, 0xF8, + 0x14, 0xA0, 0x84, 0xF8, + 0x13, 0xA0, 0x84, 0xF8, 0x12, 0xB0, 0x73, 0xE0, 0x02, 0xAA, 0x01, 0xA9, + 0x20, 0x46, 0xFF, 0xF7, + 0x46, 0xFF, 0x03, 0xAB, 0xBD, 0xF9, 0x08, 0x20, 0x21, 0x46, 0x30, 0x46, + 0xFF, 0xF7, 0x10, 0xFF, + 0x83, 0x46, 0x04, 0xAB, 0xBD, 0xF9, 0x04, 0x20, 0x21, 0x1D, 0x30, 0x46, + 0xFF, 0xF7, 0x08, 0xFF, + 0x07, 0x46, 0xBB, 0xF1, 0x01, 0x0F, 0x03, 0xD0, 0x20, 0x7D, 0x01, 0x28, + 0x4D, 0xD0, 0x4E, 0xE0, + 0xBD, 0xF9, 0x0C, 0x00, 0xBD, 0xF9, 0x0E, 0x10, 0x81, 0x42, 0x00, 0xDD, + 0x08, 0x46, 0xD9, 0xF8, + 0x00, 0x10, 0x91, 0xF8, 0xCC, 0x23, 0x02, 0xF0, 0x0F, 0x03, 0x4F, 0xEA, + 0x12, 0x1C, 0xA2, 0x7D, + 0x02, 0x2A, 0x04, 0xD0, 0x01, 0x2A, 0x05, 0xD0, 0x03, 0x2A, 0x06, 0xD0, + 0x0B, 0xE0, 0x91, 0xF8, + 0xCF, 0x13, 0x04, 0xE0, 0x91, 0xF8, 0x54, 0x14, 0x01, 0xE0, 0x91, 0xF8, + 0x2F, 0x14, 0x01, 0xF0, + 0x0F, 0x03, 0x4F, 0xEA, 0x11, 0x1C, 0x01, 0x2F, 0x0C, 0xD0, 0xCD, 0xF8, + 0x00, 0xC0, 0xBD, 0xF9, + 0x08, 0x20, 0xBD, 0xF9, 0x04, 0x10, 0x07, 0xF0, 0xDC, 0xFD, 0x21, 0x7D, + 0x01, 0x29, 0x0D, 0xD0, + 0x18, 0xE0, 0x23, 0xE0, 0xA0, 0x68, 0x30, 0x60, 0xD9, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0x80, 0x03, + 0x00, 0x06, 0x01, 0xD4, 0x4F, 0xF0, 0x00, 0x08, 0x60, 0x46, 0xEE, 0xE7, + 0x95, 0xF8, 0x41, 0x11, + 0x41, 0xB9, 0xD9, 0xF8, 0x00, 0x10, 0x91, 0xF8, 0xBC, 0x13, 0x0A, 0x09, + 0xD4, 0xF8, 0x0E, 0x10, + 0x07, 0xF0, 0xD4, 0xFD, 0xC4, 0xF8, 0x0E, 0x00, 0x01, 0xE0, 0x84, 0xF8, + 0x15, 0xA0, 0x84, 0xF8, + 0x14, 0xB0, 0xE7, 0x74, 0xB8, 0xF1, 0x00, 0x0F, 0x02, 0xD1, 0x03, 0xE0, + 0xA0, 0x68, 0x30, 0x60, + 0x30, 0x68, 0xA0, 0x60, 0x05, 0xB0, 0x40, 0x46, 0xBD, 0xE8, 0xF0, 0x8F, + 0x4C, 0x07, 0x10, 0x00, + 0x2D, 0xE9, 0xF0, 0x41, 0x17, 0x46, 0x06, 0x46, 0xDD, 0xE9, 0x06, 0xC2, + 0xC8, 0x78, 0x00, 0x25, + 0x0C, 0x46, 0x03, 0x28, 0x30, 0xD2, 0xFE, 0x48, 0xDF, 0xF8, 0xF8, 0xE3, + 0x01, 0x68, 0x91, 0xF8, + 0x0A, 0x14, 0xA1, 0x70, 0xDE, 0xF8, 0x04, 0xE0, 0xBE, 0xF1, 0x00, 0x0F, + 0x06, 0xDD, 0xD0, 0xF8, + 0x00, 0xE0, 0x9E, 0xF8, 0x0B, 0xE4, 0xA1, 0xEB, 0x0E, 0x01, 0xA1, 0x70, + 0x00, 0x68, 0x71, 0x6B, + 0xB0, 0xF8, 0x0C, 0x04, 0x81, 0x42, 0x15, 0xDD, 0xDB, 0xB2, 0x39, 0x46, + 0x60, 0x46, 0x00, 0xF0, + 0xE8, 0xFA, 0xE0, 0x78, 0x40, 0x1C, 0xC0, 0xB2, 0xE0, 0x70, 0x03, 0x28, + 0x06, 0xD0, 0xEE, 0x49, + 0xB6, 0xF9, 0x56, 0x00, 0xB1, 0xF9, 0x00, 0x10, 0x88, 0x42, 0x05, 0xDD, + 0x03, 0x20, 0xE0, 0x70, + 0x01, 0x25, 0x01, 0xE0, 0x00, 0x20, 0xE0, 0x70, 0x28, 0x46, 0xBD, 0xE8, + 0xF0, 0x81, 0x2D, 0xE9, + 0xFC, 0x5F, 0x4F, 0xF0, 0x00, 0x0B, 0x0C, 0x46, 0x81, 0x46, 0x5D, 0x46, + 0x4F, 0xF0, 0x02, 0x0A, + 0x01, 0x26, 0x00, 0xF5, 0x80, 0x57, 0x7C, 0xE0, 0xD7, 0xF8, 0xEC, 0x03, + 0x06, 0xFA, 0x05, 0xFE, + 0x10, 0xEA, 0x0E, 0x0F, 0x74, 0xD0, 0x05, 0xEB, 0x05, 0x10, 0x00, 0xEB, + 0x80, 0x01, 0x09, 0xEB, + 0x81, 0x00, 0x00, 0xF5, 0x9A, 0x71, 0x90, 0xF8, 0x3E, 0x81, 0xB0, 0xF9, + 0x0E, 0xC0, 0xB8, 0xF1, + 0x01, 0x0F, 0x0F, 0xD0, 0xB8, 0xF1, 0x02, 0x0F, 0x0C, 0xD0, 0x90, 0xF8, + 0x42, 0x00, 0x40, 0x07, + 0x51, 0xD5, 0xD2, 0x48, 0xEB, 0xB2, 0x61, 0x46, 0xB0, 0xF9, 0x08, 0x20, + 0x20, 0x46, 0x00, 0xF0, + 0xA0, 0xFA, 0x55, 0xE0, 0xCE, 0x4B, 0xB0, 0xF9, 0x54, 0x20, 0xB3, 0xF9, + 0x00, 0x30, 0x9A, 0x42, + 0x4E, 0xDB, 0xB8, 0xF1, 0x01, 0x0F, 0x03, 0xD1, 0x00, 0x22, 0x0A, 0x60, + 0x4A, 0x60, 0x0A, 0x81, + 0xC6, 0x4A, 0xB2, 0xF9, 0x00, 0x30, 0x63, 0x45, 0x03, 0xDC, 0xB2, 0xF9, + 0x02, 0x30, 0x63, 0x45, + 0x0C, 0xDA, 0xB0, 0xF8, 0x42, 0x30, 0x43, 0xF0, 0x04, 0x03, 0xA0, 0xF8, + 0x42, 0x30, 0xC3, 0x68, + 0x4B, 0x60, 0x81, 0xF8, 0x08, 0xA0, 0xB2, 0xF9, 0x00, 0x20, 0x19, 0xE0, + 0xB2, 0xF9, 0x08, 0x30, + 0x63, 0x45, 0x03, 0xDC, 0xB2, 0xF9, 0x0A, 0x30, 0x63, 0x45, 0x19, 0xDA, + 0xB0, 0xF8, 0x42, 0x30, + 0x43, 0xF0, 0x04, 0x03, 0xA0, 0xF8, 0x42, 0x30, 0x90, 0xF8, 0x3E, 0x31, + 0x01, 0x2B, 0x02, 0xD0, + 0x0B, 0x7A, 0x02, 0x2B, 0x01, 0xD1, 0xC3, 0x68, 0x4B, 0x60, 0x0E, 0x72, + 0xB2, 0xF9, 0x08, 0x20, + 0x2B, 0x46, 0xCD, 0xE9, 0x00, 0x42, 0x62, 0x46, 0xFF, 0xF7, 0x4A, 0xFF, + 0x83, 0x46, 0x0F, 0xE0, + 0x00, 0x20, 0x08, 0x72, 0x08, 0xE0, 0xA9, 0x48, 0xB0, 0xF9, 0x08, 0x10, + 0x61, 0x45, 0x07, 0xDA, + 0xB0, 0xF9, 0x0A, 0x00, 0x60, 0x45, 0x03, 0xDD, 0xA0, 0x68, 0x40, 0xEA, + 0x0E, 0x00, 0xA0, 0x60, + 0x6D, 0x1C, 0x97, 0xF9, 0xF4, 0x03, 0xA8, 0x42, 0xBF, 0xF4, 0x7E, 0xAF, + 0x20, 0x68, 0x61, 0x68, + 0x9C, 0x4A, 0x50, 0xEA, 0x01, 0x03, 0xA3, 0x68, 0x01, 0xD0, 0x23, 0xB1, + 0x04, 0xE0, 0x1B, 0xB1, + 0x82, 0xF8, 0x00, 0xA0, 0x00, 0xE0, 0x16, 0x70, 0x98, 0x4A, 0x18, 0x32, + 0x13, 0x68, 0x98, 0x43, + 0x20, 0x60, 0x50, 0x68, 0x81, 0x43, 0x61, 0x60, 0x96, 0x49, 0xA0, 0x68, + 0x09, 0x78, 0x08, 0x43, + 0x05, 0xD1, 0x92, 0x49, 0x18, 0x22, 0x18, 0x39, 0x90, 0x48, 0x0B, 0xF0, + 0x8B, 0xFB, 0x58, 0x46, + 0xBD, 0xE8, 0xFC, 0x9F, 0x8B, 0x4A, 0x10, 0xB5, 0x12, 0x78, 0x00, 0x21, + 0x01, 0x2A, 0x01, 0xD1, + 0x03, 0xB1, 0x01, 0x21, 0x90, 0xF8, 0x3E, 0x21, 0x04, 0x2A, 0x18, 0xD1, + 0x84, 0x4A, 0x12, 0x68, + 0x92, 0xF8, 0x00, 0x34, 0x5B, 0x07, 0x12, 0xD5, 0xB0, 0xF8, 0x4A, 0x30, + 0xB0, 0xF8, 0x4C, 0x40, + 0x1B, 0x1B, 0x82, 0x4C, 0xA4, 0x8A, 0xA3, 0x42, 0x09, 0xDD, 0x90, 0xF8, + 0x5B, 0x30, 0x90, 0xF8, + 0x5A, 0x00, 0x92, 0xF8, 0x09, 0x24, 0x18, 0x1A, 0x90, 0x42, 0x00, 0xDD, + 0x01, 0x21, 0x08, 0x46, + 0x10, 0xBD, 0x30, 0xB5, 0x79, 0x4D, 0x00, 0x24, 0x18, 0x35, 0x09, 0xB1, + 0x29, 0x68, 0x11, 0xB9, + 0x12, 0xB1, 0x69, 0x68, 0x01, 0xB1, 0x01, 0x24, 0x72, 0x49, 0x09, 0x78, + 0x01, 0x29, 0x01, 0xD1, + 0x03, 0xB1, 0x01, 0x24, 0x6E, 0x49, 0x09, 0x68, 0x91, 0xF8, 0x00, 0x24, + 0x52, 0x07, 0x16, 0xD5, + 0x90, 0xF8, 0x3E, 0x21, 0x04, 0x2A, 0x12, 0xD1, 0xB0, 0xF8, 0x4A, 0x20, + 0xB0, 0xF8, 0x4C, 0x30, + 0xD2, 0x1A, 0x6A, 0x4B, 0x9B, 0x8A, 0x9A, 0x42, 0x09, 0xDD, 0x90, 0xF8, + 0x5B, 0x20, 0x90, 0xF8, + 0x5A, 0x00, 0x91, 0xF8, 0x09, 0x14, 0x10, 0x1A, 0x88, 0x42, 0x00, 0xDD, + 0x01, 0x24, 0x20, 0x46, + 0x30, 0xBD, 0x2D, 0xE9, 0xF3, 0x4F, 0x8D, 0xB0, 0x5E, 0x48, 0x00, 0x25, + 0x8B, 0x46, 0x0A, 0x95, + 0x01, 0x78, 0x5E, 0x48, 0x18, 0x38, 0x01, 0x29, 0x06, 0xD1, 0xDB, 0xF8, + 0x08, 0x10, 0x19, 0xB1, + 0xD0, 0xF8, 0x1C, 0x80, 0x47, 0x6A, 0x02, 0xE0, 0xD0, 0xF8, 0x18, 0x80, + 0x07, 0x6A, 0x0D, 0x9E, + 0x00, 0x24, 0x4F, 0xF0, 0x01, 0x09, 0x06, 0xF5, 0x80, 0x56, 0x0F, 0xE1, + 0x09, 0xFA, 0x04, 0xF0, + 0xD6, 0xF8, 0xEC, 0x13, 0x0B, 0x90, 0x01, 0x42, 0x1A, 0xD0, 0x04, 0xEB, + 0x04, 0x10, 0x00, 0xEB, + 0x80, 0x01, 0x0D, 0x98, 0x00, 0xEB, 0x81, 0x0A, 0x9A, 0xF8, 0x42, 0x00, + 0x40, 0x07, 0x0F, 0xD5, + 0x0A, 0xF5, 0x9A, 0x70, 0x01, 0x90, 0xBA, 0xF9, 0x0E, 0x00, 0x02, 0x90, + 0x9A, 0xF8, 0x3E, 0x01, + 0x01, 0x28, 0x06, 0xD0, 0x02, 0x28, 0x04, 0xD0, 0x04, 0x28, 0x1F, 0xD0, + 0x05, 0x28, 0x7D, 0xD0, + 0xEB, 0xE0, 0xDB, 0xF8, 0x00, 0x10, 0xDB, 0xF8, 0x04, 0x20, 0xDB, 0xF8, + 0x08, 0x30, 0x50, 0x46, + 0xFF, 0xF7, 0x60, 0xFF, 0x01, 0x28, 0x02, 0xD1, 0x01, 0x99, 0x81, 0xF8, + 0x01, 0x90, 0xDB, 0xF8, + 0x00, 0x10, 0xDB, 0xF8, 0x04, 0x20, 0xDB, 0xF8, 0x08, 0x30, 0x50, 0x46, + 0xFF, 0xF7, 0x79, 0xFF, + 0x01, 0x28, 0xE5, 0xD1, 0x01, 0x99, 0x00, 0x20, 0x88, 0x70, 0xCE, 0xE0, + 0xDB, 0xF8, 0x00, 0x10, + 0xDB, 0xF8, 0x04, 0x20, 0xDB, 0xF8, 0x08, 0x30, 0x50, 0x46, 0xFF, 0xF7, + 0x6A, 0xFF, 0x01, 0x28, + 0x09, 0xD0, 0x01, 0x98, 0x80, 0x78, 0x48, 0xB1, 0x01, 0x99, 0x40, 0x1E, + 0x10, 0xF0, 0xFF, 0x00, + 0x88, 0x70, 0x03, 0xD0, 0x07, 0xE0, 0x01, 0x99, 0x00, 0x20, 0x88, 0x70, + 0x9A, 0xF8, 0x48, 0x11, + 0x09, 0xFA, 0x01, 0xF0, 0x05, 0x43, 0xDB, 0xF8, 0x00, 0x10, 0xDB, 0xF8, + 0x04, 0x20, 0xDB, 0xF8, + 0x08, 0x30, 0x50, 0x46, 0xFF, 0xF7, 0x26, 0xFF, 0x01, 0x28, 0x02, 0xD1, + 0x01, 0x99, 0x81, 0xF8, + 0x01, 0x90, 0x01, 0x98, 0xC0, 0x78, 0x03, 0x28, 0x1D, 0xD2, 0x01, 0x99, + 0x89, 0x78, 0xD1, 0xB1, + 0x17, 0x49, 0xDA, 0xF8, 0x34, 0x20, 0x09, 0x68, 0xB1, 0xF8, 0x0C, 0x14, + 0x8A, 0x42, 0x0F, 0xDD, + 0x40, 0x1C, 0x01, 0x99, 0xC0, 0xB2, 0x03, 0x28, 0xC8, 0x70, 0x06, 0xD0, + 0x12, 0x49, 0xBA, 0xF9, + 0x56, 0x00, 0xB1, 0xF9, 0x00, 0x10, 0x88, 0x42, 0x05, 0xDD, 0x01, 0x20, + 0x0A, 0x90, 0x02, 0xE0, + 0x01, 0x99, 0x00, 0x20, 0xC8, 0x70, 0x02, 0x98, 0x0F, 0xFA, 0x88, 0xF2, + 0x82, 0x42, 0x04, 0xDC, + 0x02, 0x98, 0x4F, 0xEA, 0x28, 0x41, 0x81, 0x42, 0x16, 0xDA, 0x01, 0x98, + 0x02, 0x21, 0xE3, 0xB2, + 0x01, 0x72, 0x01, 0x98, 0xDA, 0xF8, 0x0C, 0x10, 0x41, 0x60, 0x37, 0xE0, + 0x56, 0xE0, 0x00, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x14, 0x06, 0x10, 0x00, 0x8C, 0x06, 0x10, 0x00, + 0xA8, 0x2C, 0x10, 0x00, + 0xA0, 0x06, 0x10, 0x00, 0x20, 0x07, 0x10, 0x00, 0x38, 0xB2, 0x02, 0x99, + 0x04, 0x90, 0x88, 0x42, + 0x03, 0xDC, 0x02, 0x98, 0x39, 0x14, 0x81, 0x42, 0x25, 0xDA, 0x01, 0x98, + 0x00, 0x7A, 0x02, 0x28, + 0x06, 0xD1, 0x01, 0x99, 0x81, 0xF8, 0x08, 0x90, 0x01, 0x98, 0xDA, 0xF8, + 0x0C, 0x10, 0x41, 0x60, + 0x01, 0x98, 0x40, 0x78, 0x80, 0xB9, 0x01, 0x98, 0x53, 0x46, 0x80, 0x78, + 0x00, 0x28, 0x82, 0x48, + 0x02, 0x69, 0x04, 0xD0, 0x01, 0x98, 0x0A, 0xF1, 0x0C, 0x01, 0x00, 0x1D, + 0x02, 0xE0, 0x0A, 0xF1, + 0x10, 0x01, 0x08, 0x1F, 0x00, 0xF0, 0xE2, 0xF8, 0x04, 0x9A, 0xE3, 0xB2, + 0x58, 0x46, 0x02, 0x99, + 0x00, 0xF0, 0xCF, 0xF8, 0x31, 0xE0, 0xDB, 0xF8, 0x08, 0x00, 0x0B, 0x99, + 0x08, 0x43, 0xCB, 0xF8, + 0x08, 0x00, 0x01, 0x98, 0x80, 0x78, 0x20, 0xB1, 0x01, 0x99, 0x00, 0x22, + 0x50, 0x46, 0x09, 0x1D, + 0x03, 0xE0, 0x01, 0x22, 0x0A, 0xF1, 0x0C, 0x01, 0x50, 0x46, 0x00, 0xF0, + 0xA8, 0xF8, 0xBA, 0xF8, + 0x42, 0x00, 0x20, 0xF0, 0x04, 0x01, 0xAA, 0xF8, 0x42, 0x10, 0x16, 0xE0, + 0x01, 0x98, 0x00, 0x7A, + 0x01, 0x28, 0x12, 0xD1, 0x01, 0x98, 0x80, 0x78, 0x78, 0xB1, 0x01, 0x99, + 0x01, 0x22, 0x50, 0x46, + 0x09, 0x1D, 0x00, 0xF0, 0x94, 0xF8, 0xBA, 0xF8, 0x42, 0x00, 0x20, 0xF0, + 0x04, 0x01, 0xAA, 0xF8, + 0x42, 0x10, 0xBA, 0xF8, 0x56, 0x10, 0xAA, 0xF8, 0x54, 0x10, 0x64, 0x1C, + 0x96, 0xF9, 0xF4, 0x03, + 0xA0, 0x42, 0xBF, 0xF4, 0xEB, 0xAE, 0x5D, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0x00, 0x04, 0x80, 0x07, + 0x02, 0xD5, 0x28, 0x46, 0xFC, 0xF7, 0x6F, 0xFC, 0x59, 0x48, 0x15, 0xB1, + 0x80, 0xF8, 0x00, 0x90, + 0x01, 0xE0, 0x00, 0x21, 0x01, 0x70, 0x0A, 0x98, 0x0F, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x53, 0x49, + 0x0B, 0x68, 0x51, 0x49, 0x5A, 0x8E, 0x18, 0x39, 0x12, 0x1A, 0x08, 0x80, + 0x4A, 0x80, 0x93, 0xF8, + 0x0F, 0x34, 0x18, 0x44, 0x88, 0x80, 0xD0, 0x1A, 0xC8, 0x80, 0x70, 0x47, + 0x4B, 0x49, 0x0B, 0x68, + 0x49, 0x49, 0x5A, 0x8E, 0x18, 0x39, 0x12, 0x1A, 0x08, 0x81, 0x4A, 0x81, + 0x93, 0xF8, 0x12, 0x34, + 0x18, 0x44, 0x88, 0x81, 0xD0, 0x1A, 0xC8, 0x81, 0x70, 0x47, 0x10, 0xB5, + 0x43, 0x4C, 0x20, 0x68, + 0x90, 0xF8, 0x0E, 0x04, 0xFF, 0xF7, 0xDB, 0xFF, 0x20, 0x68, 0x90, 0xF8, + 0x0E, 0x04, 0xFF, 0xF7, + 0xE5, 0xFF, 0x22, 0x68, 0x3C, 0x49, 0x92, 0xF8, 0x10, 0x04, 0x18, 0x39, + 0x40, 0x43, 0x08, 0x61, + 0x92, 0xF8, 0x11, 0x04, 0x88, 0x82, 0x18, 0x22, 0x37, 0x48, 0x0B, 0xF0, + 0xB3, 0xF9, 0x38, 0x49, + 0x00, 0x20, 0x35, 0x4A, 0x08, 0x70, 0x37, 0x49, 0x18, 0x3A, 0x48, 0x60, + 0x10, 0x63, 0x50, 0x63, + 0x90, 0x63, 0x35, 0x4A, 0x10, 0x70, 0x08, 0x70, 0x10, 0xBD, 0xFE, 0xB5, + 0x00, 0x24, 0x06, 0x46, + 0x00, 0x94, 0x01, 0x94, 0x69, 0x46, 0x02, 0x94, 0xFF, 0xF7, 0x61, 0xFD, + 0x05, 0x46, 0x69, 0x46, + 0x30, 0x46, 0xFF, 0xF7, 0x66, 0xFE, 0x40, 0xEA, 0x05, 0x01, 0x2A, 0x48, + 0x01, 0x29, 0x01, 0xD0, + 0x41, 0x68, 0x05, 0xE0, 0x25, 0x49, 0x09, 0x68, 0x91, 0xF8, 0x0A, 0x14, + 0x49, 0x1F, 0x41, 0x60, + 0x00, 0x29, 0x04, 0xDD, 0x49, 0x1E, 0x41, 0x60, 0x21, 0x49, 0x09, 0x78, + 0x01, 0xB9, 0x44, 0x60, + 0x1D, 0x48, 0x9D, 0xE8, 0x0E, 0x00, 0x18, 0x30, 0x80, 0xE8, 0x0E, 0x00, + 0xFE, 0xBD, 0x02, 0x23, + 0x80, 0xF8, 0x3E, 0x31, 0x00, 0x23, 0x80, 0xF8, 0x42, 0x31, 0x01, 0x2A, + 0x05, 0xD0, 0x09, 0x68, + 0x01, 0x62, 0x01, 0x21, 0x80, 0xF8, 0x34, 0x11, 0x70, 0x47, 0x03, 0x22, + 0x0C, 0x30, 0x07, 0xF0, + 0x67, 0xBA, 0x10, 0xB5, 0x01, 0x24, 0x9C, 0x40, 0x91, 0x42, 0x03, 0xDA, + 0x01, 0x68, 0x21, 0x43, + 0x01, 0x60, 0x10, 0xBD, 0x41, 0x68, 0x21, 0x43, 0x41, 0x60, 0x10, 0xBD, + 0x70, 0xB5, 0x15, 0x46, + 0x0A, 0x46, 0x06, 0x46, 0x01, 0x46, 0x1C, 0x46, 0x10, 0x46, 0x07, 0xF0, + 0x74, 0xFA, 0xA8, 0x42, + 0x09, 0xDD, 0x00, 0x22, 0x31, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0xD1, 0xFF, + 0x34, 0xF8, 0x42, 0x0F, + 0x20, 0xF0, 0x04, 0x00, 0x20, 0x80, 0x70, 0xBD, 0xA8, 0x2C, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0xA4, 0x06, 0x10, 0x00, 0x14, 0x06, 0x10, 0x00, 0xA5, 0x06, 0x10, 0x00, + 0x10, 0xB5, 0x41, 0xF2, + 0xE4, 0x41, 0x82, 0x48, 0x0B, 0xF0, 0x92, 0xF9, 0x40, 0xF2, 0x3C, 0x41, + 0x80, 0x48, 0x0B, 0xF0, + 0x8D, 0xF9, 0x80, 0x48, 0xFF, 0x21, 0x80, 0xF8, 0xF4, 0x13, 0x00, 0xF0, + 0x95, 0xFC, 0xFF, 0xF7, + 0xE3, 0xFA, 0xFF, 0xF7, 0x5A, 0xFF, 0x00, 0xF0, 0xFB, 0xF8, 0xFD, 0xF7, + 0x6A, 0xFB, 0xFE, 0xF7, + 0x8C, 0xF8, 0xBD, 0xE8, 0x10, 0x40, 0xFE, 0xF7, 0x05, 0xBE, 0x70, 0xB5, + 0x76, 0x4D, 0x00, 0x24, + 0x72, 0x48, 0xAC, 0x71, 0x00, 0xF0, 0x86, 0xFC, 0x74, 0x4E, 0x30, 0x68, + 0x90, 0xF8, 0x40, 0x04, + 0xC1, 0x06, 0x04, 0xD5, 0xC0, 0x07, 0x02, 0xD0, 0x6C, 0x48, 0xFF, 0xF7, + 0xCF, 0xF9, 0x30, 0x68, + 0x90, 0xF8, 0x00, 0x04, 0xC0, 0x07, 0x05, 0xD0, 0x68, 0x48, 0xFF, 0xF7, + 0x5E, 0xFF, 0x67, 0x48, + 0x00, 0xF0, 0xD7, 0xF8, 0x65, 0x48, 0xFD, 0xF7, 0x4C, 0xFB, 0x64, 0x48, + 0xFE, 0xF7, 0x73, 0xF8, + 0x63, 0x48, 0x80, 0xF8, 0x38, 0x44, 0x63, 0x48, 0xB0, 0xF8, 0xF8, 0x03, + 0xA5, 0xF8, 0x1F, 0x00, + 0x70, 0xBD, 0x70, 0xB5, 0x5E, 0x4D, 0x60, 0x4E, 0x95, 0xF8, 0x38, 0x04, + 0x88, 0xB3, 0xB0, 0x71, + 0x29, 0x46, 0x5A, 0x48, 0x00, 0xF0, 0x88, 0xFC, 0x5C, 0x4C, 0x20, 0x68, + 0x90, 0xF8, 0x40, 0x04, + 0xC1, 0x06, 0x04, 0xD5, 0xC0, 0x07, 0x02, 0xD0, 0x54, 0x48, 0xFF, 0xF7, + 0x9F, 0xF9, 0x20, 0x68, + 0x90, 0xF8, 0x00, 0x04, 0xC0, 0x07, 0x02, 0xD0, 0x50, 0x48, 0xFF, 0xF7, + 0x2E, 0xFF, 0x20, 0x68, + 0x90, 0xF8, 0x80, 0x03, 0xC0, 0x07, 0x02, 0xD0, 0x4C, 0x48, 0xFF, 0xF7, + 0x27, 0xF9, 0x4B, 0x48, + 0x00, 0xF0, 0x9F, 0xF8, 0x49, 0x48, 0xFD, 0xF7, 0x14, 0xFB, 0x48, 0x48, + 0xFE, 0xF7, 0x3B, 0xF8, + 0x00, 0x20, 0x85, 0xF8, 0x38, 0x04, 0x47, 0x48, 0xB0, 0xF8, 0xF8, 0x03, + 0xA6, 0xF8, 0x1F, 0x00, + 0x70, 0xBD, 0xFF, 0xE7, 0xFF, 0xF7, 0x99, 0xFF, 0xF5, 0xE7, 0x10, 0xB5, + 0x40, 0x4C, 0x01, 0x46, + 0x94, 0xF8, 0x38, 0x04, 0x0F, 0x28, 0x0B, 0xD2, 0x00, 0xEB, 0xC0, 0x00, + 0x04, 0xEB, 0xC0, 0x00, + 0x48, 0x22, 0x0B, 0xF0, 0xA7, 0xF8, 0x94, 0xF8, 0x38, 0x04, 0x40, 0x1C, + 0x84, 0xF8, 0x38, 0x04, + 0x10, 0xBD, 0x10, 0xB5, 0x00, 0xF5, 0x80, 0x50, 0x00, 0x21, 0xD0, 0xF8, + 0xEC, 0x33, 0x01, 0x22, + 0x02, 0xFA, 0x01, 0xF4, 0x23, 0x42, 0x0B, 0xD1, 0x8A, 0x40, 0x13, 0x43, + 0xC0, 0xF8, 0xEC, 0x33, + 0x90, 0xF9, 0xF4, 0x23, 0x8A, 0x42, 0x01, 0xDA, 0x80, 0xF8, 0xF4, 0x13, + 0x48, 0xB2, 0x10, 0xBD, + 0x49, 0x1C, 0x0F, 0x29, 0xEC, 0xDB, 0x4F, 0xF0, 0xFF, 0x30, 0x10, 0xBD, + 0x10, 0xB5, 0x00, 0xF5, + 0x80, 0x50, 0x91, 0xF8, 0x4C, 0x41, 0x01, 0x23, 0xD0, 0xF8, 0xEC, 0x23, + 0xA3, 0x40, 0x9A, 0x43, + 0xC0, 0xF8, 0xEC, 0x23, 0x00, 0x22, 0x81, 0xF8, 0x3E, 0x21, 0x90, 0xF9, + 0xF4, 0x23, 0x91, 0xF9, + 0x4C, 0x11, 0x8A, 0x42, 0x07, 0xD1, 0xD0, 0xF8, 0xEC, 0x13, 0xB1, 0xFA, + 0x81, 0xF1, 0xC1, 0xF1, + 0x1F, 0x01, 0x80, 0xF8, 0xF4, 0x13, 0x10, 0xBD, 0x30, 0xB5, 0x00, 0xF5, + 0x80, 0x50, 0x00, 0x22, + 0xD0, 0xF8, 0xF0, 0x43, 0x01, 0x23, 0x00, 0xBF, 0x03, 0xFA, 0x02, 0xF5, + 0x2C, 0x42, 0x06, 0xD1, + 0x93, 0x40, 0x1C, 0x43, 0xC0, 0xF8, 0xF0, 0x43, 0x81, 0xF8, 0x4D, 0x21, + 0x30, 0xBD, 0x52, 0x1C, + 0x52, 0xB2, 0x0A, 0x2A, 0xF0, 0xDB, 0xFF, 0x20, 0x81, 0xF8, 0x4D, 0x01, + 0x30, 0xBD, 0x10, 0xB5, + 0x00, 0xF5, 0x80, 0x50, 0x91, 0xF8, 0x4D, 0x41, 0x01, 0x23, 0xD0, 0xF8, + 0xF0, 0x23, 0xA3, 0x40, + 0x9A, 0x43, 0xC0, 0xF8, 0xF0, 0x23, 0xFF, 0x20, 0x81, 0xF8, 0x4D, 0x01, + 0x10, 0xBD, 0x04, 0x48, + 0x70, 0x47, 0x03, 0x48, 0x90, 0xF8, 0x38, 0x04, 0x70, 0x47, 0x00, 0x00, + 0xCC, 0x2C, 0x10, 0x00, + 0xB0, 0x41, 0x10, 0x00, 0xCC, 0x3C, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, + 0x4C, 0x07, 0x10, 0x00, + 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x5F, 0x00, 0x24, 0x06, 0x46, 0x01, 0x27, + 0xDF, 0xF8, 0x0C, 0x81, + 0xDF, 0xF8, 0x0C, 0x91, 0xDF, 0xF8, 0x0C, 0xA1, 0x4F, 0xF0, 0x05, 0x0B, + 0x00, 0xF5, 0x80, 0x55, + 0x76, 0xE0, 0x00, 0xBF, 0xD5, 0xF8, 0xEC, 0x03, 0x07, 0xFA, 0x04, 0xF1, + 0x08, 0x42, 0x6D, 0xD0, + 0x04, 0xEB, 0x04, 0x10, 0x00, 0xEB, 0x80, 0x00, 0x06, 0xEB, 0x80, 0x01, + 0x91, 0xF8, 0x3E, 0x01, + 0x01, 0x28, 0x04, 0xD0, 0x02, 0x28, 0x02, 0xD0, 0x04, 0x28, 0x3B, 0xD0, + 0x5E, 0xE0, 0x91, 0xF8, + 0x3F, 0x01, 0x03, 0x28, 0x06, 0xD0, 0x04, 0x28, 0x04, 0xD0, 0x02, 0x28, + 0x21, 0xD0, 0x01, 0x28, + 0x29, 0xD0, 0x53, 0xE0, 0x30, 0x48, 0xB1, 0xF8, 0x42, 0x20, 0xB0, 0xF9, + 0x00, 0x00, 0x53, 0x07, + 0x01, 0xD5, 0xB8, 0xF9, 0x00, 0x00, 0x13, 0x07, 0x02, 0xD5, 0x2C, 0x48, + 0xB0, 0xF9, 0x00, 0x00, + 0xB1, 0xF9, 0x54, 0x30, 0x83, 0x42, 0x41, 0xDA, 0xD0, 0x05, 0x06, 0xD5, + 0xB9, 0xF9, 0x00, 0x00, + 0x83, 0x42, 0x02, 0xDD, 0x81, 0xF8, 0x3F, 0x71, 0x38, 0xE0, 0x30, 0x46, + 0xFF, 0xF7, 0x56, 0xFF, + 0x34, 0xE0, 0x91, 0xF8, 0x42, 0x20, 0x00, 0x20, 0x52, 0x07, 0x01, 0xD5, + 0xB8, 0xF9, 0x00, 0x00, + 0xB1, 0xF9, 0x54, 0x20, 0x03, 0xE0, 0xB1, 0xF9, 0x54, 0x20, 0xB9, 0xF9, + 0x00, 0x00, 0x82, 0x42, + 0xEB, 0xDB, 0x23, 0xE0, 0x91, 0xF8, 0x40, 0x00, 0x10, 0xF0, 0x06, 0x0F, + 0x1E, 0xD0, 0x91, 0xF8, + 0x42, 0x00, 0x40, 0x07, 0x1A, 0xD4, 0x17, 0x4A, 0x15, 0x48, 0x12, 0x78, + 0xB0, 0xF9, 0x00, 0x00, + 0x01, 0x2A, 0x01, 0xD1, 0xBA, 0xF9, 0x00, 0x00, 0x91, 0xF8, 0x3F, 0x21, + 0x03, 0x2A, 0x02, 0xD0, + 0x02, 0x2A, 0x05, 0xD0, 0x0A, 0xE0, 0xB1, 0xF9, 0x54, 0x20, 0xBA, 0xF9, + 0x00, 0x00, 0x01, 0xE0, + 0xB1, 0xF9, 0x54, 0x20, 0x82, 0x42, 0x01, 0xDA, 0x81, 0xF8, 0x3E, 0xB1, + 0x64, 0x1C, 0x64, 0xB2, + 0x95, 0xF9, 0xF4, 0x03, 0xA0, 0x42, 0x85, 0xDA, 0xBD, 0xE8, 0xF0, 0x9F, + 0xA0, 0x06, 0x10, 0x00, + 0x90, 0x06, 0x10, 0x00, 0x92, 0x06, 0x10, 0x00, 0x8C, 0x06, 0x10, 0x00, + 0xAA, 0x06, 0x10, 0x00, + 0x94, 0x06, 0x10, 0x00, 0xA5, 0x06, 0x10, 0x00, 0x90, 0xF8, 0x40, 0x10, + 0x09, 0x06, 0x14, 0xD5, + 0xB0, 0xF8, 0x42, 0x10, 0x0A, 0x07, 0x0C, 0xD4, 0xFE, 0x4A, 0x12, 0x68, + 0x92, 0xF8, 0x40, 0x34, + 0x5B, 0x06, 0x06, 0xD5, 0x92, 0xF8, 0x80, 0x23, 0x52, 0x06, 0x02, 0xD4, + 0x01, 0x22, 0x80, 0xF8, + 0x70, 0x20, 0x41, 0xF0, 0x08, 0x01, 0xA0, 0xF8, 0x42, 0x10, 0x70, 0x47, + 0xB0, 0xF8, 0x40, 0x10, + 0xC9, 0x05, 0x14, 0xD5, 0xB0, 0xF8, 0x42, 0x10, 0x0A, 0x06, 0x0C, 0xD4, + 0xF1, 0x4A, 0x12, 0x68, + 0x92, 0xF8, 0x20, 0x34, 0x9B, 0x07, 0x06, 0xD5, 0x92, 0xF8, 0x80, 0x23, + 0x52, 0x06, 0x02, 0xD4, + 0x01, 0x22, 0x80, 0xF8, 0x70, 0x20, 0x41, 0xF0, 0x80, 0x01, 0xA0, 0xF8, + 0x42, 0x10, 0x70, 0x47, + 0x2D, 0xE9, 0xF0, 0x47, 0x82, 0x46, 0x92, 0xF8, 0x40, 0x00, 0x15, 0x46, + 0x0C, 0x46, 0x02, 0x28, + 0x01, 0xD1, 0x28, 0x69, 0xE8, 0x60, 0x04, 0xF1, 0x0C, 0x07, 0x4F, 0xF0, + 0x00, 0x08, 0x4F, 0xF0, + 0xFF, 0x39, 0x05, 0xF1, 0x0C, 0x06, 0x63, 0xB3, 0x01, 0x20, 0x84, 0xF8, + 0x3E, 0x01, 0x95, 0xF8, + 0x40, 0x00, 0x84, 0xF8, 0x3F, 0x01, 0x84, 0xF8, 0x4D, 0x91, 0x84, 0xF8, + 0x42, 0x81, 0x84, 0xF8, + 0x43, 0x81, 0xA4, 0xF8, 0x42, 0x80, 0xC4, 0xF8, 0x2C, 0x80, 0x84, 0xF8, + 0x41, 0x81, 0x84, 0xF8, + 0x44, 0x81, 0x95, 0xF8, 0x42, 0x00, 0x84, 0xF8, 0x47, 0x01, 0x68, 0x8E, + 0xA4, 0xF8, 0x56, 0x00, + 0x95, 0xF8, 0x41, 0x00, 0x84, 0xF8, 0x48, 0x01, 0xE8, 0x68, 0x20, 0x62, + 0x03, 0x22, 0x31, 0x46, + 0x20, 0x46, 0x07, 0xF0, 0x1D, 0xF8, 0x03, 0x22, 0x31, 0x46, 0x38, 0x46, + 0x07, 0xF0, 0x18, 0xF8, + 0x14, 0xE0, 0x11, 0x46, 0x20, 0x46, 0x00, 0xF0, 0x5F, 0xFB, 0xE0, 0x6A, + 0x03, 0x22, 0x40, 0x1C, + 0xE0, 0x62, 0x31, 0x46, 0x20, 0x46, 0x06, 0xF0, 0xFF, 0xFF, 0x03, 0x22, + 0x31, 0x46, 0x38, 0x46, + 0x06, 0xF0, 0xFA, 0xFF, 0x94, 0xF8, 0x46, 0x01, 0x84, 0xF8, 0x47, 0x01, + 0x95, 0xF8, 0x40, 0x00, + 0x84, 0xF8, 0x3F, 0x01, 0x95, 0xF8, 0x42, 0x00, 0x84, 0xF8, 0x46, 0x01, + 0xE8, 0x8C, 0xA4, 0xF8, + 0x44, 0x00, 0x28, 0x8D, 0xA4, 0xF8, 0x46, 0x00, 0x68, 0x8D, 0xA4, 0xF8, + 0x48, 0x00, 0xE8, 0x8D, + 0xA4, 0xF8, 0x4A, 0x00, 0x28, 0x8E, 0xA4, 0xF8, 0x4C, 0x00, 0x28, 0x8B, + 0xA4, 0xF8, 0x4E, 0x00, + 0xB5, 0xF9, 0x32, 0x00, 0xA4, 0xF8, 0x54, 0x00, 0xA9, 0x69, 0x61, 0x63, + 0xE9, 0x69, 0xA1, 0x63, + 0x29, 0x6A, 0xE1, 0x63, 0xA9, 0x8E, 0xA4, 0xF8, 0x58, 0x10, 0xA9, 0x8C, + 0xA4, 0xF8, 0x40, 0x10, + 0xD5, 0xF8, 0x36, 0x10, 0xC4, 0xF8, 0x5A, 0x10, 0x69, 0x69, 0xE1, 0x61, + 0x95, 0xF8, 0x43, 0x10, + 0x84, 0xF8, 0x49, 0x11, 0x95, 0xF8, 0x44, 0x10, 0x84, 0xF8, 0x4A, 0x11, + 0xB4, 0xF9, 0x56, 0x10, + 0x81, 0x42, 0x01, 0xDA, 0xA4, 0xF8, 0x56, 0x00, 0xC4, 0xF8, 0x50, 0x81, + 0x84, 0xF8, 0x4B, 0x91, + 0xA8, 0x8C, 0x80, 0x05, 0xB4, 0xF8, 0x42, 0x00, 0x02, 0xD5, 0x40, 0xF4, + 0x80, 0x70, 0x01, 0xE0, + 0x20, 0xF4, 0x80, 0x70, 0xA4, 0xF8, 0x42, 0x00, 0x21, 0x46, 0x50, 0x46, + 0x00, 0xF0, 0xD3, 0xFA, + 0x20, 0x46, 0xFF, 0xF7, 0x21, 0xFF, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x47, + 0x36, 0xE7, 0xF0, 0xB5, + 0xB1, 0xF9, 0x02, 0x60, 0xB2, 0xF9, 0x02, 0x50, 0x78, 0x24, 0x06, 0xFB, + 0x05, 0xF7, 0x00, 0x2F, + 0x2A, 0xDD, 0xB1, 0xF9, 0x00, 0x70, 0xB2, 0xF9, 0x00, 0xC0, 0x07, 0xFB, + 0x0C, 0xF7, 0x00, 0x2F, + 0x22, 0xDD, 0x76, 0x43, 0x5D, 0x43, 0x96, 0xFB, 0xF5, 0xF5, 0x2D, 0xB2, + 0x45, 0x80, 0xB1, 0xF9, + 0x00, 0x10, 0xB2, 0xF9, 0x00, 0x20, 0x49, 0x43, 0x5A, 0x43, 0x91, 0xFB, + 0xF2, 0xF1, 0x0A, 0xB2, + 0x02, 0x80, 0x78, 0x2D, 0x00, 0xDD, 0x44, 0x80, 0xB0, 0xF9, 0x02, 0x30, + 0x6F, 0xF0, 0x77, 0x01, + 0x8B, 0x42, 0x00, 0xDA, 0x41, 0x80, 0x78, 0x2A, 0x00, 0xDD, 0x04, 0x80, + 0xB0, 0xF9, 0x00, 0x20, + 0x8A, 0x42, 0x00, 0xDA, 0x01, 0x80, 0xF0, 0xBD, 0x00, 0x21, 0x41, 0x80, + 0xFA, 0xE7, 0x2D, 0xE9, + 0xFF, 0x4F, 0xDF, 0xF8, 0xD4, 0x81, 0x0F, 0x46, 0x72, 0x4E, 0xD8, 0xF8, + 0x08, 0x10, 0x8F, 0xB0, + 0x00, 0x20, 0x08, 0x60, 0x30, 0x68, 0xB0, 0xF8, 0x82, 0x53, 0x0A, 0xF0, + 0x77, 0xFF, 0x01, 0x28, + 0x04, 0xD1, 0x30, 0x68, 0xB0, 0xF8, 0x84, 0x03, 0x00, 0xB1, 0x05, 0x46, + 0x0A, 0xF0, 0x64, 0xFF, + 0x80, 0xB1, 0x30, 0x68, 0x69, 0x49, 0xB0, 0xF8, 0x86, 0x53, 0xB0, 0xF8, + 0x8A, 0x03, 0x09, 0x68, + 0x88, 0x42, 0x07, 0xDA, 0x0A, 0xF0, 0x62, 0xFF, 0x01, 0x28, 0x03, 0xD1, + 0x30, 0x68, 0xB0, 0xF8, + 0x88, 0x03, 0x05, 0x44, 0xDF, 0xF8, 0x88, 0xB1, 0x62, 0x48, 0x63, 0x4B, + 0xBB, 0xF9, 0x00, 0x20, + 0x62, 0x49, 0xDF, 0xF8, 0x8C, 0xA1, 0x12, 0xB1, 0x01, 0x2A, 0x3E, 0xD0, + 0x7B, 0xE0, 0xB0, 0xF9, + 0x00, 0x00, 0xBA, 0xF9, 0x00, 0x20, 0xD1, 0x46, 0x42, 0x43, 0x03, 0xEB, + 0x42, 0x04, 0x42, 0x00, + 0x09, 0x68, 0x20, 0x46, 0x0A, 0xF0, 0xE9, 0xFD, 0xD8, 0xF8, 0x04, 0x20, + 0x05, 0x21, 0x92, 0xFB, + 0xF1, 0xF3, 0x01, 0xFB, 0x13, 0x22, 0x41, 0xF6, 0x5A, 0x61, 0x11, 0x44, + 0x21, 0x80, 0x55, 0x49, + 0x40, 0x46, 0x49, 0x79, 0x61, 0x80, 0x54, 0x49, 0x09, 0x88, 0xA1, 0x80, + 0x53, 0x49, 0x09, 0x88, + 0xE1, 0x80, 0x53, 0x49, 0x09, 0x88, 0x21, 0x81, 0x52, 0x49, 0x09, 0x88, + 0x61, 0x81, 0x52, 0x49, + 0x09, 0x88, 0xA1, 0x81, 0x51, 0x49, 0x09, 0x88, 0xE1, 0x81, 0xB9, 0xF8, + 0x00, 0x10, 0x49, 0x1C, + 0x09, 0xB2, 0xA9, 0xF8, 0x00, 0x10, 0x42, 0x68, 0x52, 0x1C, 0xC8, 0xF8, + 0x04, 0x20, 0x05, 0x29, + 0x41, 0xDB, 0x00, 0x21, 0xA9, 0xF8, 0x00, 0x10, 0x3D, 0xE0, 0xBA, 0xF9, + 0x00, 0x40, 0x0A, 0x2C, + 0x36, 0xDA, 0xB0, 0xF9, 0x00, 0x00, 0xD1, 0x46, 0x00, 0xFB, 0x04, 0xF2, + 0x03, 0xEB, 0x42, 0x04, + 0x42, 0x00, 0x09, 0x68, 0x20, 0x46, 0x0A, 0xF0, 0xA8, 0xFD, 0xD8, 0xF8, + 0x04, 0x20, 0x05, 0x21, + 0x92, 0xFB, 0xF1, 0xF3, 0x01, 0xFB, 0x13, 0x22, 0x41, 0xF6, 0x5A, 0x61, + 0x11, 0x44, 0x21, 0x80, + 0x34, 0x49, 0x40, 0x46, 0x49, 0x79, 0x61, 0x80, 0x33, 0x49, 0x09, 0x88, + 0xA1, 0x80, 0x33, 0x49, + 0x09, 0x88, 0xE1, 0x80, 0x32, 0x49, 0x09, 0x88, 0x21, 0x81, 0x32, 0x49, + 0x09, 0x88, 0x61, 0x81, + 0x31, 0x49, 0x09, 0x88, 0xA1, 0x81, 0x31, 0x49, 0x09, 0x88, 0xE1, 0x81, + 0xB9, 0xF8, 0x00, 0x10, + 0x49, 0x1C, 0xA9, 0xF8, 0x00, 0x10, 0x41, 0x68, 0x49, 0x1C, 0xC8, 0xF8, + 0x04, 0x10, 0x02, 0xE0, + 0x02, 0x20, 0xAB, 0xF8, 0x00, 0x00, 0x6D, 0x43, 0x02, 0x95, 0x30, 0x68, + 0x0F, 0x9E, 0x00, 0x25, + 0x90, 0xF8, 0x8C, 0x03, 0x04, 0x90, 0x06, 0xF5, 0x80, 0x56, 0x96, 0xE0, + 0x4F, 0xF0, 0x01, 0x09, + 0xD6, 0xF8, 0xEC, 0x03, 0x09, 0xFA, 0x05, 0xF1, 0x08, 0x42, 0x7D, 0xD0, + 0x05, 0xEB, 0x05, 0x10, + 0x00, 0xEB, 0x80, 0x01, 0x0F, 0x98, 0x00, 0xEB, 0x81, 0x04, 0x94, 0xF8, + 0x3E, 0x01, 0x07, 0x28, + 0x72, 0xD0, 0x21, 0x46, 0x20, 0x1D, 0x06, 0xF0, 0xBE, 0xFE, 0x00, 0x90, + 0xB0, 0xF5, 0x80, 0x5F, + 0x08, 0xDD, 0x01, 0x46, 0xAD, 0x20, 0x06, 0xF0, 0x69, 0xF9, 0xAB, 0xF8, + 0x00, 0x90, 0x05, 0x20, + 0xAA, 0xF8, 0x00, 0x00, 0x04, 0x99, 0x00, 0x98, 0x48, 0x43, 0x00, 0xFB, + 0x01, 0xF9, 0x02, 0x99, + 0x89, 0x45, 0x1D, 0xE0, 0x4C, 0x07, 0x10, 0x00, 0x1C, 0x06, 0x10, 0x00, + 0x24, 0x07, 0x10, 0x00, + 0x84, 0x07, 0x10, 0x00, 0xFE, 0x06, 0x10, 0x00, 0x20, 0x4D, 0x01, 0x20, + 0x10, 0x07, 0x10, 0x00, + 0x82, 0x07, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, 0x86, 0x07, 0x10, 0x00, + 0x88, 0x07, 0x10, 0x00, + 0x8A, 0x07, 0x10, 0x00, 0x8C, 0x07, 0x10, 0x00, 0x8E, 0x07, 0x10, 0x00, + 0x90, 0x07, 0x10, 0x00, + 0x00, 0xDA, 0x89, 0x46, 0x22, 0x46, 0x21, 0x1D, 0x08, 0xA8, 0x06, 0xF0, + 0x7A, 0xFE, 0x22, 0x1D, + 0x11, 0x1D, 0x0A, 0xA8, 0x06, 0xF0, 0x75, 0xFE, 0xBD, 0xF9, 0x20, 0x00, + 0x64, 0x30, 0xC8, 0x28, + 0x04, 0xD8, 0xBD, 0xF9, 0x22, 0x00, 0x64, 0x30, 0xC8, 0x28, 0x01, 0xD9, + 0x01, 0x23, 0x00, 0xE0, + 0x03, 0x23, 0x0A, 0xAA, 0x08, 0xA9, 0x09, 0xA8, 0xFF, 0xF7, 0xA1, 0xFE, + 0x60, 0x88, 0xBD, 0xF8, + 0x26, 0x10, 0x08, 0x44, 0xAD, 0xF8, 0x2E, 0x00, 0x20, 0x88, 0xBD, 0xF8, + 0x24, 0x10, 0x00, 0x24, + 0x08, 0x44, 0xAD, 0xF8, 0x2C, 0x00, 0x1A, 0xE0, 0x04, 0xEB, 0xC4, 0x00, + 0x07, 0xEB, 0xC0, 0x01, + 0x0B, 0xA8, 0x0C, 0x31, 0x06, 0xF0, 0x57, 0xFE, 0x48, 0x45, 0x0E, 0xDA, + 0xD8, 0xF8, 0x08, 0x10, + 0x0A, 0x68, 0x02, 0xEB, 0x42, 0x02, 0x00, 0xE0, 0x0D, 0xE0, 0x01, 0xEB, + 0x42, 0x02, 0x50, 0x60, + 0x54, 0x72, 0x15, 0x72, 0x08, 0x68, 0x40, 0x1C, 0x08, 0x60, 0x64, 0x1C, + 0xE4, 0xB2, 0x97, 0xF8, + 0x38, 0x04, 0xA0, 0x42, 0xE0, 0xD8, 0x6D, 0x1C, 0x6D, 0xB2, 0x96, 0xF9, + 0xF4, 0x03, 0xA8, 0x42, + 0xBF, 0xF6, 0x64, 0xAF, 0xD8, 0xF8, 0x08, 0x00, 0x45, 0x46, 0x01, 0x68, + 0x00, 0x29, 0x78, 0xD0, + 0x00, 0xF0, 0xC2, 0xF9, 0x00, 0x26, 0x4F, 0xF0, 0x04, 0x09, 0xDF, 0xF8, + 0xC4, 0xA3, 0x4F, 0xF0, + 0x06, 0x0B, 0x6A, 0xE0, 0x06, 0xEB, 0x46, 0x01, 0x00, 0xEB, 0x41, 0x00, + 0x90, 0xF9, 0x08, 0x40, + 0x90, 0xF9, 0x09, 0x30, 0x11, 0x98, 0x02, 0x68, 0x01, 0x20, 0x00, 0xFA, + 0x04, 0xF1, 0x0A, 0x42, + 0x5A, 0xD1, 0xDD, 0xF8, 0x48, 0xC0, 0x00, 0xFA, 0x03, 0xF8, 0xDC, 0xF8, + 0x00, 0xC0, 0x1C, 0xEA, + 0x08, 0x0F, 0x51, 0xD1, 0x11, 0x98, 0x0A, 0x43, 0x02, 0x60, 0x12, 0x98, + 0x12, 0x99, 0x00, 0x68, + 0x40, 0xEA, 0x08, 0x00, 0x08, 0x60, 0x04, 0xEB, 0x04, 0x10, 0x00, 0xEB, + 0x80, 0x01, 0x0F, 0x98, + 0x00, 0xEB, 0x81, 0x04, 0x03, 0xEB, 0xC3, 0x00, 0x07, 0xEB, 0xC0, 0x02, + 0x00, 0x23, 0x21, 0x46, + 0x0F, 0x98, 0xFF, 0xF7, 0x7D, 0xFD, 0x94, 0xF8, 0x3E, 0x01, 0x03, 0x28, + 0x04, 0xD0, 0x04, 0x28, + 0x04, 0xD0, 0x06, 0x28, 0x08, 0xD0, 0x2F, 0xE0, 0x01, 0x20, 0x00, 0xE0, + 0x00, 0x20, 0x84, 0xF8, + 0x41, 0x01, 0x84, 0xF8, 0x3E, 0x91, 0x27, 0xE0, 0x84, 0xF8, 0x3E, 0x91, + 0x94, 0xF8, 0x40, 0x00, + 0x10, 0xF0, 0x06, 0x0F, 0x20, 0xD0, 0x94, 0xF8, 0x42, 0x00, 0x40, 0x07, + 0x1C, 0xD4, 0xCA, 0x49, + 0xC8, 0x48, 0x09, 0x78, 0xB0, 0xF9, 0x00, 0x00, 0x01, 0x29, 0x01, 0xD1, + 0xBA, 0xF9, 0x00, 0x00, + 0x94, 0xF8, 0x3F, 0x11, 0x03, 0x29, 0x02, 0xD0, 0x02, 0x29, 0x09, 0xD0, + 0x0C, 0xE0, 0xB4, 0xF9, + 0x54, 0x10, 0xBA, 0xF9, 0x00, 0x00, 0x05, 0xE0, 0x84, 0xF8, 0x3E, 0xB1, + 0x04, 0xE0, 0x08, 0xE0, + 0xB4, 0xF9, 0x54, 0x10, 0x81, 0x42, 0xF7, 0xDB, 0x76, 0x1C, 0xA8, 0x68, + 0x01, 0x68, 0xB1, 0x42, + 0x90, 0xDC, 0x13, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xB8, 0x48, 0x00, 0x21, + 0x01, 0x70, 0x81, 0x60, + 0xC1, 0x60, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x41, 0x05, 0x46, 0x41, 0xF2, + 0x38, 0x40, 0x2E, 0x21, + 0x28, 0x44, 0x0A, 0xF0, 0xE3, 0xFC, 0x00, 0x24, 0x05, 0xF5, 0x80, 0x56, + 0x01, 0x27, 0x4F, 0xF0, + 0x05, 0x08, 0x1B, 0xE0, 0xD6, 0xF8, 0xEC, 0x03, 0x07, 0xFA, 0x04, 0xF1, + 0x08, 0x42, 0x14, 0xD0, + 0x04, 0xEB, 0x04, 0x10, 0x00, 0xEB, 0x80, 0x00, 0x05, 0xEB, 0x80, 0x01, + 0x91, 0xF8, 0x3E, 0x01, + 0x03, 0x28, 0x04, 0xD0, 0x04, 0x28, 0x02, 0xD0, 0x02, 0x28, 0x03, 0xD0, + 0x05, 0xE0, 0x81, 0xF8, + 0x3E, 0x81, 0x02, 0xE0, 0x28, 0x46, 0xFF, 0xF7, 0xE1, 0xFB, 0x64, 0x1C, + 0x96, 0xF9, 0xF4, 0x03, + 0xA0, 0x42, 0xDF, 0xDA, 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xFC, 0x47, + 0x04, 0x46, 0x00, 0x25, + 0x9A, 0x48, 0x0E, 0x46, 0x00, 0x95, 0x01, 0x21, 0x08, 0x30, 0x01, 0x95, + 0x04, 0xF0, 0x87, 0xF8, + 0x96, 0x48, 0x05, 0x21, 0x0C, 0x30, 0x04, 0xF0, 0x82, 0xF8, 0x41, 0xF2, + 0x38, 0x40, 0x2E, 0x21, + 0x20, 0x44, 0x0A, 0xF0, 0xA3, 0xFC, 0x91, 0x4F, 0xFF, 0x22, 0x2D, 0x21, + 0xF8, 0x68, 0x0A, 0xF0, + 0x73, 0xFC, 0x3D, 0x70, 0x04, 0xF5, 0x80, 0x57, 0x4F, 0xF0, 0x01, 0x08, + 0xD7, 0xF8, 0xEC, 0x03, + 0x58, 0xB3, 0x6B, 0x46, 0x01, 0xAA, 0x31, 0x46, 0x20, 0x46, 0xFF, 0xF7, + 0xC0, 0xFD, 0x4F, 0xF0, + 0x05, 0x09, 0x1E, 0xE0, 0xD7, 0xF8, 0xEC, 0x13, 0x08, 0xFA, 0x05, 0xF0, + 0x01, 0x42, 0x17, 0xD0, + 0x01, 0x99, 0x08, 0x42, 0x14, 0xD1, 0x05, 0xEB, 0x05, 0x10, 0x00, 0xEB, + 0x80, 0x00, 0x04, 0xEB, + 0x80, 0x01, 0x91, 0xF8, 0x3E, 0x01, 0x03, 0x28, 0x04, 0xD0, 0x04, 0x28, + 0x02, 0xD0, 0x02, 0x28, + 0x03, 0xD0, 0x05, 0xE0, 0x81, 0xF8, 0x3E, 0x91, 0x02, 0xE0, 0x20, 0x46, + 0xFF, 0xF7, 0x8E, 0xFB, + 0x6D, 0x1C, 0x97, 0xF9, 0xF4, 0x03, 0xA8, 0x42, 0xDC, 0xDA, 0x00, 0x25, + 0x47, 0x46, 0x1A, 0xE0, + 0x00, 0x99, 0x07, 0xFA, 0x05, 0xF0, 0x08, 0x42, 0x14, 0xD1, 0x20, 0x46, + 0xFF, 0xF7, 0x61, 0xFB, + 0x00, 0x28, 0x0F, 0xDB, 0x00, 0xEB, 0x00, 0x11, 0x01, 0xEB, 0x81, 0x01, + 0x04, 0xEB, 0x81, 0x01, + 0x05, 0xEB, 0xC5, 0x02, 0x81, 0xF8, 0x4C, 0x01, 0x06, 0xEB, 0xC2, 0x02, + 0x01, 0x23, 0x20, 0x46, + 0xFF, 0xF7, 0x96, 0xFC, 0x6D, 0x1C, 0x96, 0xF8, 0x38, 0x04, 0xA8, 0x42, + 0xE0, 0xD8, 0x63, 0x48, + 0x01, 0x21, 0x08, 0x30, 0x04, 0xF0, 0x38, 0xF8, 0x60, 0x48, 0x05, 0x21, + 0x0C, 0x30, 0x04, 0xF0, + 0x33, 0xF8, 0xBD, 0xE8, 0xFC, 0x87, 0x30, 0xB5, 0x5C, 0x4A, 0x91, 0xF8, + 0x46, 0x51, 0xD4, 0x68, + 0x63, 0x5D, 0xFF, 0x2B, 0x05, 0xD1, 0x13, 0x78, 0x63, 0x55, 0x0F, 0x2B, + 0x01, 0xD2, 0x5B, 0x1C, + 0x13, 0x70, 0x91, 0xF8, 0x46, 0x21, 0xA2, 0x5C, 0x81, 0xF8, 0x46, 0x21, + 0x00, 0xEB, 0x42, 0x02, + 0x02, 0xF5, 0x80, 0x52, 0x91, 0xF8, 0x4C, 0x51, 0xB2, 0xF8, 0x38, 0x34, + 0x01, 0x24, 0xAC, 0x40, + 0x23, 0x43, 0xA2, 0xF8, 0x38, 0x34, 0x91, 0xF8, 0x46, 0x11, 0x41, 0xF2, + 0x56, 0x42, 0x10, 0x44, + 0x0A, 0x5C, 0x52, 0x1C, 0x0A, 0x54, 0x30, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, + 0x04, 0x46, 0x91, 0xF8, + 0x40, 0x00, 0x00, 0x26, 0x0D, 0x46, 0x01, 0x28, 0x01, 0xD1, 0x84, 0xF8, + 0x44, 0x61, 0x94, 0xF8, + 0x3F, 0x01, 0x43, 0x4F, 0xDF, 0xF8, 0x0C, 0x81, 0x01, 0x28, 0x1F, 0xD1, + 0x95, 0xF8, 0x40, 0x00, + 0x03, 0x28, 0x4D, 0xD1, 0x94, 0xF8, 0x3E, 0x01, 0x02, 0x28, 0x04, 0xD0, + 0x03, 0x28, 0x06, 0xD0, + 0x04, 0x28, 0x04, 0xD0, 0x1E, 0xE0, 0x20, 0x46, 0xFC, 0xF7, 0xC0, 0xFD, + 0x0E, 0xE0, 0xD8, 0xF8, + 0x00, 0x10, 0x94, 0xF8, 0x44, 0x01, 0x91, 0xF8, 0x4B, 0x13, 0x01, 0xF0, + 0x0F, 0x01, 0x88, 0x42, + 0x02, 0xD8, 0x39, 0x78, 0x01, 0x29, 0x06, 0xD0, 0x84, 0xF8, 0x44, 0x61, + 0x95, 0xF8, 0x40, 0x00, + 0x03, 0x28, 0x07, 0xD0, 0x08, 0xE0, 0x40, 0x1C, 0x84, 0xF8, 0x44, 0x01, + 0x01, 0x20, 0x85, 0xF8, + 0x40, 0x00, 0x01, 0xE0, 0x84, 0xF8, 0x45, 0x61, 0x94, 0xF8, 0x3F, 0x01, + 0x03, 0x28, 0x1F, 0xD1, + 0x95, 0xF8, 0x40, 0x00, 0x01, 0x28, 0x1B, 0xD1, 0x94, 0xF8, 0x3E, 0x01, + 0x04, 0x28, 0x17, 0xD1, + 0x38, 0x78, 0xB0, 0xB9, 0xD8, 0xF8, 0x00, 0x00, 0xB4, 0xF9, 0x56, 0x10, + 0xB0, 0xF8, 0x52, 0x23, + 0x91, 0x42, 0x0E, 0xDA, 0x94, 0xF8, 0x45, 0x11, 0x90, 0xF8, 0x54, 0x03, + 0x81, 0x42, 0x07, 0xD2, + 0x03, 0x20, 0x85, 0xF8, 0x40, 0x00, 0x94, 0xF8, 0x45, 0x01, 0x40, 0x1C, + 0x84, 0xF8, 0x45, 0x01, + 0xF0, 0xE6, 0x84, 0xF8, 0x45, 0x61, 0xED, 0xE6, 0x7C, 0xB5, 0x00, 0x21, + 0x1C, 0xE0, 0x01, 0xEB, + 0x41, 0x03, 0x4A, 0x1C, 0x00, 0xEB, 0x43, 0x03, 0x12, 0xE0, 0x02, 0xEB, + 0x42, 0x04, 0x00, 0xEB, + 0x44, 0x04, 0x5E, 0x68, 0x65, 0x68, 0xAE, 0x42, 0x09, 0xDD, 0x00, 0x96, + 0x1E, 0x89, 0xAD, 0xF8, + 0x04, 0x60, 0x5D, 0x60, 0x25, 0x89, 0x1D, 0x81, 0x00, 0x9D, 0x65, 0x60, + 0x26, 0x81, 0x52, 0x1C, + 0x04, 0x68, 0x94, 0x42, 0xE9, 0xDC, 0x49, 0x1C, 0x02, 0x68, 0x8A, 0x42, + 0xDF, 0xDC, 0x7C, 0xBD, + 0x92, 0x06, 0x10, 0x00, 0x94, 0x06, 0x10, 0x00, 0xA5, 0x06, 0x10, 0x00, + 0x1C, 0x06, 0x10, 0x00, + 0xF9, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x2D, 0xE9, 0xF8, 0x4F, + 0x00, 0x22, 0x91, 0x46, + 0x15, 0x46, 0x14, 0x46, 0x00, 0x92, 0xFE, 0x4A, 0xFE, 0x4B, 0x12, 0x68, + 0xB3, 0xF9, 0x00, 0xC0, + 0xFD, 0x4B, 0x17, 0x8E, 0x1E, 0x68, 0x67, 0x45, 0x60, 0xD1, 0x86, 0x46, + 0xFB, 0x48, 0x02, 0xF1, + 0x32, 0x0A, 0x8B, 0x46, 0x90, 0xF8, 0x00, 0xC0, 0xF9, 0x48, 0x07, 0x78, + 0x4D, 0xE0, 0x3A, 0x46, + 0x43, 0xE0, 0x00, 0xBF, 0x3A, 0xF8, 0x12, 0x10, 0x3E, 0xF8, 0x12, 0x00, + 0x3B, 0xF8, 0x12, 0x30, + 0x08, 0x1A, 0xC9, 0x1A, 0x00, 0xB2, 0x0B, 0xB2, 0x00, 0x28, 0x01, 0xDB, + 0x01, 0x46, 0x00, 0xE0, + 0x41, 0x42, 0x49, 0x45, 0x06, 0xDD, 0x00, 0x28, 0x01, 0xDB, 0x01, 0x46, + 0x00, 0xE0, 0x41, 0x42, + 0x0F, 0xFA, 0x81, 0xF9, 0x19, 0x1A, 0x01, 0xD4, 0x88, 0x46, 0x01, 0xE0, + 0xC1, 0xF1, 0x00, 0x08, + 0xA8, 0x45, 0x05, 0xDD, 0x00, 0x29, 0x01, 0xDB, 0x0D, 0x46, 0x00, 0xE0, + 0x4D, 0x42, 0x2D, 0xB2, + 0x00, 0x29, 0x00, 0xDA, 0x49, 0x42, 0xB6, 0xF8, 0xE2, 0x83, 0x41, 0x45, + 0x15, 0xDD, 0x00, 0x2B, + 0x00, 0xDA, 0x5B, 0x42, 0x01, 0x1E, 0x00, 0xDA, 0x41, 0x42, 0x8B, 0x42, + 0x02, 0xDD, 0x64, 0x1C, + 0xA4, 0xB2, 0x0A, 0xE0, 0x00, 0x28, 0x00, 0xDA, 0x40, 0x42, 0xB6, 0xF8, + 0xE4, 0x13, 0x88, 0x42, + 0x03, 0xDD, 0x4F, 0xF0, 0x00, 0x0C, 0x64, 0x46, 0x01, 0xE0, 0x52, 0x1E, + 0xBA, 0xD1, 0x0A, 0xEB, + 0x47, 0x0A, 0x0E, 0xEB, 0x47, 0x0E, 0x0B, 0xEB, 0x47, 0x0B, 0xBC, 0xF1, + 0x01, 0x0C, 0xAE, 0xD2, + 0x96, 0xF8, 0xE6, 0x03, 0xA0, 0x42, 0x01, 0xD2, 0x01, 0x20, 0x00, 0x90, + 0x96, 0xF8, 0xE7, 0x13, + 0xCC, 0x48, 0x00, 0x9A, 0x06, 0xF0, 0x71, 0xFB, 0xCB, 0x49, 0x21, 0xF8, + 0x25, 0x5F, 0x21, 0xF8, + 0x02, 0x9C, 0x8C, 0x70, 0xBD, 0xE8, 0xF8, 0x8F, 0x10, 0xB5, 0x0C, 0x46, + 0xC3, 0x49, 0x09, 0x78, + 0x4A, 0x00, 0x01, 0x46, 0xC5, 0x48, 0x0A, 0xF0, 0x50, 0xFA, 0xC1, 0x48, + 0x21, 0x46, 0x00, 0x78, + 0x42, 0x00, 0xC3, 0x48, 0x0A, 0xF0, 0x49, 0xFA, 0xC2, 0x49, 0x01, 0x20, + 0x08, 0x70, 0x10, 0xBD, + 0xB8, 0x49, 0x10, 0xB5, 0xB1, 0xF9, 0x00, 0x10, 0x4A, 0x00, 0x01, 0x46, + 0xBE, 0x48, 0x00, 0x68, + 0x0A, 0xF0, 0x3B, 0xFA, 0xBD, 0x49, 0x01, 0x20, 0x08, 0x70, 0x10, 0xBD, + 0x10, 0xB5, 0x01, 0x23, + 0x0A, 0xE0, 0x00, 0xBF, 0x30, 0xF9, 0x13, 0x40, 0x00, 0x2C, 0x00, 0xDA, + 0x64, 0x42, 0x8C, 0x42, + 0x01, 0xDD, 0x01, 0x20, 0x10, 0xBD, 0x5B, 0x1C, 0x93, 0x42, 0xF3, 0xDB, + 0x00, 0x20, 0x10, 0xBD, + 0x2D, 0xE9, 0xFF, 0x5F, 0xDF, 0xF8, 0xAC, 0xB2, 0x00, 0x24, 0xAB, 0xF1, + 0x01, 0x0B, 0xDF, 0xF8, + 0x98, 0x92, 0xCB, 0xF8, 0x04, 0x40, 0x8B, 0xF8, 0x00, 0x40, 0xD9, 0xF8, + 0x00, 0x00, 0x1F, 0x46, + 0x26, 0x46, 0x90, 0xF8, 0xE0, 0x03, 0x25, 0x46, 0xA0, 0x46, 0xC0, 0x07, + 0x0E, 0xD0, 0x03, 0x20, + 0xF3, 0xF7, 0xF7, 0xFC, 0xA4, 0x48, 0x01, 0x68, 0x00, 0x98, 0xFF, 0xF7, + 0x2D, 0xFF, 0x04, 0x46, + 0x11, 0x25, 0x03, 0x20, 0xF3, 0xF7, 0x08, 0xFD, 0x00, 0x2C, 0x63, 0xD1, + 0xA0, 0x48, 0x00, 0x78, + 0x10, 0xF0, 0x30, 0x0F, 0x5E, 0xD0, 0xFA, 0xF7, 0x21, 0xFD, 0xD9, 0xF8, + 0x00, 0x00, 0xDF, 0xF8, + 0x74, 0xA2, 0x90, 0xF8, 0xE0, 0x03, 0x80, 0x07, 0x0B, 0xD5, 0x9B, 0x4A, + 0x9B, 0x49, 0xDA, 0xF8, + 0x00, 0x00, 0x00, 0xF0, 0xFB, 0xF8, 0x04, 0x00, 0x4F, 0xF0, 0x30, 0x05, + 0x4F, 0xF0, 0x01, 0x06, + 0x48, 0xD1, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0xE1, 0x03, 0xC0, 0x07, + 0x0B, 0xD0, 0x94, 0x4A, + 0x94, 0x49, 0xDA, 0xF8, 0x00, 0x00, 0x00, 0xF0, 0x7B, 0xF8, 0x04, 0x00, + 0x4F, 0xF0, 0x30, 0x05, + 0x4F, 0xF0, 0x01, 0x06, 0x36, 0xD1, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0xE1, 0x03, 0x80, 0x07, + 0x0B, 0xD5, 0x8B, 0x4A, 0x8B, 0x49, 0xDA, 0xF8, 0x00, 0x00, 0x00, 0xF0, + 0xA4, 0xF8, 0x04, 0x00, + 0x4F, 0xF0, 0x31, 0x05, 0x4F, 0xF0, 0x01, 0x06, 0x24, 0xD1, 0x87, 0x48, + 0x00, 0x78, 0x01, 0x28, + 0x20, 0xD1, 0x86, 0x48, 0x01, 0x7E, 0x86, 0x48, 0x00, 0x7E, 0x01, 0xFB, + 0x00, 0xF2, 0x19, 0x2A, + 0x03, 0xD2, 0x05, 0x29, 0x01, 0xD8, 0x05, 0x28, 0x02, 0xD9, 0x32, 0x25, + 0x01, 0x26, 0x11, 0xE0, + 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0xE1, 0x03, 0x40, 0x07, 0x0B, 0xD5, + 0x03, 0x20, 0xF3, 0xF7, + 0x90, 0xFC, 0x71, 0x48, 0x7B, 0x4A, 0x00, 0x99, 0x00, 0x68, 0xFA, 0xF7, + 0x7E, 0xFE, 0x03, 0x20, + 0xF3, 0xF7, 0xA2, 0xFC, 0x0A, 0xF0, 0x00, 0xFB, 0x01, 0x46, 0x77, 0x48, + 0x01, 0x70, 0x54, 0xB3, + 0x6E, 0xB1, 0x87, 0xF8, 0x00, 0x80, 0x29, 0x46, 0x05, 0x20, 0x05, 0xF0, + 0x9C, 0xFD, 0x00, 0x98, + 0xFF, 0xF7, 0x46, 0xFF, 0xDD, 0xE9, 0x01, 0x01, 0xFF, 0xF7, 0x2E, 0xFF, + 0x17, 0xE0, 0x01, 0x20, + 0x38, 0x70, 0x8B, 0xF8, 0x00, 0x50, 0xDB, 0xF8, 0x04, 0x10, 0x41, 0xF0, + 0x02, 0x01, 0xCB, 0xF8, + 0x04, 0x10, 0xD9, 0xF8, 0x00, 0x20, 0x92, 0xF8, 0x50, 0x32, 0xDB, 0x07, + 0x03, 0xD1, 0x92, 0xF8, + 0x80, 0x22, 0xD2, 0x07, 0x03, 0xD0, 0x41, 0xF0, 0x08, 0x01, 0xCB, 0xF8, + 0x04, 0x10, 0x01, 0x20, + 0x04, 0xB0, 0xBD, 0xE8, 0xF0, 0x9F, 0x87, 0xF8, 0x00, 0x80, 0x00, 0x78, + 0xF8, 0xE7, 0x4D, 0x48, + 0x00, 0x21, 0x40, 0x1E, 0x41, 0x60, 0x01, 0x70, 0xA0, 0xF8, 0x01, 0x10, + 0xC1, 0x70, 0x70, 0x47, + 0x2D, 0xE9, 0xF7, 0x4F, 0xDF, 0xF8, 0x10, 0x81, 0x93, 0x46, 0x0B, 0x46, + 0xD8, 0xF8, 0x00, 0x00, + 0x00, 0x25, 0x2C, 0x46, 0x90, 0xF8, 0xEC, 0x73, 0xB0, 0xF9, 0xE8, 0x63, + 0xB0, 0xF9, 0xEA, 0xA3, + 0x3E, 0x48, 0x31, 0x46, 0x02, 0x78, 0x18, 0x46, 0xFB, 0xF7, 0x21, 0xFF, + 0x81, 0x46, 0x3C, 0x48, + 0x31, 0x46, 0x02, 0x78, 0x58, 0x46, 0xFB, 0xF7, 0x1A, 0xFF, 0x01, 0x46, + 0xB9, 0xF1, 0x00, 0x0F, + 0x00, 0xD0, 0x51, 0xB9, 0x33, 0x48, 0x51, 0x46, 0xB0, 0xF9, 0x00, 0x20, + 0x00, 0x98, 0x00, 0xF0, + 0xBE, 0xF8, 0x04, 0x46, 0xB8, 0x42, 0x00, 0xD9, 0x01, 0x25, 0xD8, 0xF8, + 0x00, 0x00, 0x2A, 0x46, + 0x90, 0xF8, 0xED, 0x13, 0x2F, 0x48, 0x40, 0x1C, 0x06, 0xF0, 0x37, 0xFA, + 0x2E, 0x49, 0x81, 0xF8, + 0x31, 0x40, 0xBD, 0xE8, 0xFE, 0x8F, 0x2D, 0xE9, 0xF0, 0x47, 0x27, 0x4E, + 0x89, 0x46, 0x92, 0x46, + 0x31, 0x68, 0x24, 0x4A, 0x00, 0x25, 0x91, 0xF8, 0xF2, 0x73, 0xB1, 0xF9, + 0xF0, 0x83, 0x2C, 0x46, + 0xB1, 0xF9, 0xEE, 0x13, 0xB2, 0xF9, 0x00, 0x20, 0xFB, 0xF7, 0xF7, 0xFE, + 0x88, 0xB9, 0x1F, 0x48, + 0x41, 0x46, 0x02, 0x78, 0x48, 0x46, 0x00, 0xF0, 0x92, 0xF8, 0x04, 0x46, + 0x1C, 0x48, 0x41, 0x46, + 0x02, 0x78, 0x50, 0x46, 0x00, 0xF0, 0x8B, 0xF8, 0x20, 0x44, 0xC4, 0xB2, + 0xBC, 0x42, 0x00, 0xD9, + 0x01, 0x25, 0x30, 0x68, 0x2A, 0x46, 0x90, 0xF8, 0xF3, 0x13, 0x16, 0x48, + 0x80, 0x1C, 0x06, 0xF0, + 0x04, 0xFA, 0x15, 0x49, 0x81, 0xF8, 0x32, 0x40, 0xBD, 0xE8, 0xF0, 0x87, + 0x2D, 0xE9, 0xF0, 0x5F, + 0x0D, 0x4E, 0x83, 0x46, 0x0B, 0x46, 0x30, 0x68, 0x20, 0x49, 0x00, 0x25, + 0x90, 0xF8, 0xF5, 0x73, + 0xB0, 0xF9, 0xF6, 0xC3, 0xB0, 0xF9, 0xFA, 0x93, 0x09, 0x78, 0x92, 0x46, + 0x2C, 0x46, 0x09, 0xB1, + 0xB0, 0xF9, 0xF8, 0xC3, 0x1A, 0x48, 0x00, 0x78, 0xB0, 0xB3, 0x1A, 0x48, + 0x00, 0x78, 0x34, 0xE0, + 0x50, 0x07, 0x10, 0x00, 0xFE, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, + 0xEE, 0x06, 0x10, 0x00, 0x2D, 0x06, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, + 0x7E, 0x4A, 0x01, 0x20, + 0xA8, 0x4A, 0x01, 0x20, 0x7A, 0x07, 0x10, 0x00, 0x1C, 0x07, 0x10, 0x00, + 0x79, 0x07, 0x10, 0x00, + 0x04, 0x07, 0x10, 0x00, 0x10, 0x07, 0x10, 0x00, 0xF2, 0x2A, 0x10, 0x00, + 0xC8, 0x2A, 0x10, 0x00, + 0xBE, 0x0B, 0x01, 0x20, 0x94, 0x0B, 0x01, 0x20, 0x66, 0x05, 0x10, 0x00, + 0x18, 0x2A, 0x10, 0x00, + 0x58, 0x2A, 0x10, 0x00, 0x60, 0x2B, 0x10, 0x00, 0x76, 0x06, 0x10, 0x00, + 0xF9, 0x06, 0x10, 0x00, + 0x74, 0x05, 0x10, 0x00, 0x64, 0x05, 0x10, 0x00, 0x01, 0xE0, 0x90, 0xB1, + 0x1C, 0xE0, 0x1C, 0x48, + 0x61, 0x46, 0x02, 0x78, 0x18, 0x46, 0xFF, 0xF7, 0x61, 0xFE, 0x80, 0x46, + 0x19, 0x48, 0x61, 0x46, + 0x02, 0x78, 0x50, 0x46, 0xFF, 0xF7, 0x5A, 0xFE, 0x01, 0x46, 0xB8, 0xF1, + 0x00, 0x0F, 0x00, 0xD0, + 0x51, 0xB9, 0x15, 0x48, 0x49, 0x46, 0xB0, 0xF9, 0x00, 0x20, 0x58, 0x46, + 0x00, 0xF0, 0x0F, 0xF8, + 0x04, 0x46, 0xB8, 0x42, 0x00, 0xD9, 0x01, 0x25, 0x30, 0x68, 0x2A, 0x46, + 0x90, 0xF8, 0xFC, 0x13, + 0x0E, 0x48, 0x06, 0xF0, 0x8A, 0xF9, 0x0E, 0x49, 0x81, 0xF8, 0x31, 0x40, + 0x09, 0xE7, 0x10, 0xB5, + 0x04, 0x46, 0x00, 0x20, 0x09, 0xE0, 0x00, 0xBF, 0x34, 0xF9, 0x12, 0x30, + 0x00, 0x2B, 0x00, 0xDA, + 0x5B, 0x42, 0x8B, 0x42, 0x01, 0xDD, 0x40, 0x1C, 0xC0, 0xB2, 0x52, 0x1E, + 0xF4, 0xD2, 0x10, 0xBD, + 0xED, 0x06, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, 0xFE, 0x06, 0x10, 0x00, + 0x2E, 0x06, 0x10, 0x00, + 0x0A, 0x44, 0x01, 0x20, 0x2D, 0xE9, 0xFF, 0x4F, 0x87, 0xB0, 0x00, 0x20, + 0x81, 0x46, 0x03, 0x90, + 0x02, 0x90, 0x01, 0x90, 0xFF, 0x48, 0x88, 0x46, 0x93, 0x46, 0x00, 0x68, + 0xB0, 0xF8, 0xB0, 0x02, + 0x06, 0x90, 0x89, 0x78, 0x50, 0x68, 0x0A, 0xF0, 0xD1, 0xF9, 0x00, 0x90, + 0x98, 0xF8, 0x02, 0x50, + 0x98, 0xF8, 0x03, 0x00, 0x05, 0x90, 0x32, 0xE0, 0x07, 0x98, 0x98, 0xF8, + 0x00, 0x40, 0x00, 0xEB, + 0xC5, 0x00, 0x04, 0x90, 0x98, 0xF8, 0x01, 0xA0, 0x1F, 0xE0, 0x04, 0x98, + 0x22, 0x46, 0x00, 0x21, + 0xD0, 0xE9, 0x00, 0x67, 0x01, 0x20, 0x09, 0xF0, 0xF9, 0xFF, 0x06, 0x40, + 0x0F, 0x40, 0x3E, 0x43, + 0x12, 0xD0, 0x00, 0x98, 0x06, 0x99, 0x30, 0xF9, 0x14, 0x00, 0x88, 0x42, + 0x0C, 0xDD, 0x02, 0x99, + 0x81, 0x44, 0x04, 0xFB, 0x00, 0x11, 0x02, 0x91, 0x01, 0x99, 0x05, 0xFB, + 0x00, 0x10, 0x01, 0x90, + 0x03, 0x98, 0x40, 0x1C, 0x80, 0xB2, 0x03, 0x90, 0x64, 0x1C, 0xA2, 0x45, + 0xDD, 0xDA, 0xE2, 0x49, + 0x00, 0x98, 0x6D, 0x1C, 0x09, 0x78, 0x00, 0xEB, 0x41, 0x00, 0x00, 0x90, + 0x05, 0x98, 0xA8, 0x42, + 0xCA, 0xDA, 0xDC, 0x48, 0x00, 0x25, 0x04, 0x68, 0x01, 0x98, 0xA1, 0x8E, + 0xC2, 0x17, 0xA1, 0xFB, + 0x00, 0x36, 0x05, 0xFB, 0x00, 0x60, 0x01, 0xFB, 0x02, 0x02, 0x4F, 0xF6, + 0xFF, 0x76, 0xA3, 0xFB, + 0x06, 0x07, 0x02, 0xFB, 0x06, 0x72, 0x03, 0xFB, 0x05, 0x21, 0x94, 0xF8, + 0x31, 0x30, 0x30, 0x34, + 0x5B, 0x1E, 0x89, 0xFB, 0x03, 0x23, 0x09, 0xF0, 0xCC, 0xFF, 0x72, 0x10, + 0x80, 0x18, 0xB0, 0x46, + 0x41, 0xF1, 0x00, 0x01, 0x42, 0x46, 0x00, 0x23, 0x09, 0xF0, 0xC3, 0xFF, + 0x07, 0x46, 0x02, 0x98, + 0x61, 0x88, 0xC2, 0x17, 0xA1, 0xFB, 0x00, 0x36, 0x05, 0xFB, 0x00, 0x60, + 0x01, 0xFB, 0x02, 0x01, + 0x42, 0x46, 0xA3, 0xFB, 0x02, 0x06, 0x01, 0xFB, 0x02, 0x61, 0x03, 0xFB, + 0x05, 0x11, 0x23, 0x78, + 0x5B, 0x1E, 0x89, 0xFB, 0x03, 0x23, 0x09, 0xF0, 0xAC, 0xFF, 0x47, 0xF6, + 0xFF, 0x72, 0x80, 0x18, + 0x41, 0xF1, 0x00, 0x01, 0x42, 0x46, 0x00, 0x23, 0x09, 0xF0, 0xA3, 0xFF, + 0xCB, 0xF8, 0x1C, 0x90, + 0x03, 0x99, 0xAB, 0xF8, 0x28, 0x10, 0x0A, 0x99, 0x48, 0x60, 0x0A, 0x99, + 0x0F, 0x60, 0x0B, 0xB0, + 0xBD, 0xE8, 0xF0, 0x8F, 0x2D, 0xE9, 0xFF, 0x4F, 0x81, 0x46, 0xB2, 0x48, + 0x00, 0x26, 0x8A, 0x46, + 0x00, 0x68, 0x14, 0x46, 0x95, 0xB0, 0x90, 0xF8, 0x21, 0x03, 0x4F, 0xF6, + 0xFF, 0x75, 0x32, 0x46, + 0x31, 0x46, 0x43, 0x07, 0xAA, 0xF1, 0x01, 0x07, 0x4C, 0xD5, 0x00, 0x07, + 0x02, 0xD5, 0x8C, 0xB3, + 0xBC, 0x42, 0x48, 0xDA, 0x68, 0x46, 0xD4, 0x46, 0xA3, 0x46, 0x00, 0x23, + 0x08, 0xE0, 0x00, 0xBF, + 0x39, 0xF8, 0x13, 0x40, 0x00, 0xEB, 0x43, 0x08, 0x5B, 0x1C, 0xA8, 0xF8, + 0x02, 0x40, 0xDB, 0xB2, + 0x63, 0x45, 0xF5, 0xD3, 0x43, 0x88, 0x03, 0x80, 0x00, 0xEB, 0x4C, 0x04, + 0x30, 0xF8, 0x1C, 0x30, + 0x63, 0x80, 0x01, 0x23, 0x10, 0xE0, 0x00, 0xBF, 0x00, 0xEB, 0x43, 0x04, + 0x34, 0xF8, 0x02, 0x8C, + 0x64, 0x88, 0x44, 0x44, 0x30, 0xF8, 0x13, 0x80, 0x04, 0xEB, 0x48, 0x04, + 0x09, 0xEB, 0x43, 0x08, + 0x5B, 0x1C, 0x28, 0xF8, 0x02, 0x4C, 0xDB, 0xB2, 0x63, 0x45, 0xED, 0xD9, + 0x93, 0x4B, 0xD8, 0x46, + 0x00, 0x20, 0x09, 0xE0, 0x1B, 0xE0, 0x00, 0xBF, 0x39, 0xF9, 0x10, 0x40, + 0x9C, 0x42, 0x01, 0xDD, + 0x23, 0x46, 0x80, 0x46, 0x40, 0x1C, 0xC0, 0xB2, 0x60, 0x45, 0xF5, 0xD3, + 0x5F, 0xEA, 0x08, 0x04, + 0x01, 0xD1, 0xBD, 0xF9, 0x00, 0x20, 0xBC, 0x42, 0x04, 0xDB, 0x69, 0x46, + 0x01, 0xEB, 0x4A, 0x00, + 0x30, 0xF9, 0x02, 0x1C, 0x1C, 0xB1, 0x09, 0xEB, 0x44, 0x00, 0x30, 0xF9, + 0x02, 0x2C, 0x39, 0xF9, + 0x14, 0xA0, 0xBC, 0x42, 0x03, 0xDA, 0x09, 0xEB, 0x44, 0x00, 0xB0, 0xF9, + 0x02, 0x10, 0x10, 0x46, + 0x88, 0x46, 0x8A, 0x42, 0x01, 0xDD, 0x80, 0x46, 0x08, 0x46, 0x8A, 0x1A, + 0xA2, 0xFB, 0x05, 0x1C, + 0xD3, 0x17, 0x03, 0xFB, 0x05, 0xC3, 0x02, 0xFB, 0x06, 0x3C, 0x0A, 0xEB, + 0x08, 0x02, 0x40, 0x42, + 0x02, 0xEB, 0x40, 0x02, 0x08, 0x46, 0xD3, 0x17, 0x61, 0x46, 0x09, 0xF0, + 0x12, 0xFF, 0xA4, 0xFB, + 0x05, 0x3C, 0x00, 0x22, 0x02, 0xFB, 0x05, 0xC2, 0x04, 0xFB, 0x06, 0x22, + 0x1B, 0x18, 0x4A, 0x41, + 0x18, 0x99, 0xA3, 0xFB, 0x01, 0x0C, 0xCC, 0x17, 0x02, 0xFB, 0x01, 0xC1, + 0x03, 0xFB, 0x04, 0x11, + 0xFB, 0x17, 0x3A, 0x46, 0x09, 0xF0, 0xFD, 0xFE, 0x04, 0x46, 0x0F, 0x46, + 0x02, 0x22, 0x00, 0x23, + 0x28, 0x46, 0x31, 0x46, 0x09, 0xF0, 0xF5, 0xFE, 0x00, 0x19, 0x79, 0x41, + 0x2A, 0x46, 0x33, 0x46, + 0x09, 0xF0, 0xEF, 0xFE, 0x19, 0xB0, 0x53, 0xE7, 0x2D, 0xE9, 0xFF, 0x4F, + 0x9F, 0xB0, 0x00, 0x20, + 0x1B, 0x90, 0x16, 0x90, 0x1C, 0x90, 0x0C, 0x46, 0x90, 0x46, 0x89, 0x78, + 0x50, 0x68, 0x0A, 0xF0, + 0x8D, 0xF8, 0x13, 0x90, 0x94, 0xF8, 0x02, 0x90, 0x94, 0xF8, 0x03, 0xB0, + 0x2E, 0xE0, 0x1F, 0x98, + 0x25, 0x78, 0x00, 0xEB, 0xC9, 0x00, 0x1D, 0x90, 0x94, 0xF8, 0x01, 0xA0, + 0x1A, 0xE0, 0x1D, 0x98, + 0x2A, 0x46, 0x00, 0x21, 0xD0, 0xE9, 0x00, 0x67, 0x01, 0x20, 0x09, 0xF0, + 0xB7, 0xFE, 0x06, 0x40, + 0x0F, 0x40, 0x3E, 0x43, 0x0C, 0xD0, 0x13, 0x98, 0x1C, 0x99, 0x30, 0xF9, + 0x15, 0x00, 0x88, 0x42, + 0x06, 0xDD, 0x16, 0x99, 0x08, 0x44, 0x16, 0x90, 0x1B, 0x98, 0x40, 0x1C, + 0x80, 0xB2, 0x1B, 0x90, + 0x6D, 0x1C, 0xED, 0xB2, 0xAA, 0x45, 0xE2, 0xD2, 0x43, 0x49, 0x13, 0x98, + 0x09, 0x78, 0x00, 0xEB, + 0x41, 0x00, 0x13, 0x90, 0x09, 0xF1, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x09, + 0xCB, 0x45, 0xCE, 0xD2, + 0x16, 0x98, 0xC8, 0xF8, 0x1C, 0x00, 0x1B, 0x98, 0xA8, 0xF8, 0x28, 0x00, + 0x98, 0xF8, 0x3E, 0x70, + 0x98, 0xF8, 0x3F, 0x90, 0x4C, 0x21, 0x68, 0x46, 0x09, 0xF0, 0x60, 0xFF, + 0xA1, 0x78, 0xD8, 0xF8, + 0x04, 0x00, 0x0A, 0xF0, 0x43, 0xF8, 0x34, 0x4A, 0xA1, 0x78, 0x6D, 0x46, + 0x12, 0x78, 0x07, 0xE0, + 0x30, 0xF8, 0x17, 0x30, 0x25, 0xF8, 0x11, 0x30, 0x49, 0x1C, 0x00, 0xEB, + 0x42, 0x00, 0xC9, 0xB2, + 0xE3, 0x78, 0x8B, 0x42, 0xF4, 0xD2, 0x2B, 0x4E, 0x4A, 0x46, 0x30, 0x68, + 0xB0, 0xF9, 0x34, 0x30, + 0x90, 0xF8, 0x31, 0x10, 0x28, 0x46, 0xFF, 0xF7, 0xE5, 0xFE, 0x22, 0x99, + 0x08, 0x60, 0x4C, 0x21, + 0x68, 0x46, 0x09, 0xF0, 0x3B, 0xFF, 0x49, 0x46, 0xD8, 0xF8, 0x04, 0x00, + 0x0A, 0xF0, 0x1E, 0xF8, + 0x21, 0x78, 0x05, 0xE0, 0x30, 0xF8, 0x11, 0x20, 0x25, 0xF8, 0x11, 0x20, + 0x49, 0x1C, 0xC9, 0xB2, + 0x62, 0x78, 0x8A, 0x42, 0xF6, 0xD2, 0x30, 0x68, 0x3A, 0x46, 0xB0, 0xF9, + 0x32, 0x30, 0x90, 0xF8, + 0x30, 0x10, 0x68, 0x46, 0xFF, 0xF7, 0xC6, 0xFE, 0x22, 0x99, 0x48, 0x60, + 0x23, 0xB0, 0xBF, 0xE6, + 0x10, 0xB5, 0x14, 0x49, 0x43, 0x68, 0x00, 0x22, 0x09, 0x68, 0x00, 0x2B, + 0x01, 0xDA, 0x42, 0x60, + 0x03, 0xE0, 0x4C, 0x8E, 0xA3, 0x42, 0x00, 0xDD, 0x44, 0x60, 0x03, 0x68, + 0x00, 0x2B, 0x01, 0xDA, + 0x02, 0x60, 0x10, 0xBD, 0x89, 0x8E, 0x8B, 0x42, 0xFB, 0xDD, 0x01, 0x60, + 0x10, 0xBD, 0x2D, 0xE9, + 0xFF, 0x47, 0x14, 0x46, 0x88, 0x46, 0x81, 0x46, 0x00, 0x27, 0x01, 0x26, + 0x6B, 0x46, 0xFF, 0xF7, + 0x01, 0xFE, 0x07, 0x48, 0x03, 0x4D, 0x00, 0x78, 0x78, 0xB1, 0x28, 0x68, + 0x90, 0xF8, 0x07, 0x05, + 0x00, 0x07, 0x07, 0xE0, 0x4C, 0x07, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, + 0x00, 0x80, 0xFF, 0xFF, + 0xA4, 0x06, 0x10, 0x00, 0x01, 0xD5, 0x04, 0x27, 0x3E, 0x46, 0x94, 0xF8, + 0x40, 0x00, 0x03, 0x28, + 0x04, 0xD0, 0x02, 0x28, 0x06, 0xD0, 0x01, 0x28, 0x14, 0xD0, 0x1C, 0xE0, + 0x28, 0x68, 0x06, 0xE0, + 0x39, 0x46, 0x15, 0xE0, 0x28, 0x68, 0x90, 0xF8, 0x21, 0x13, 0x89, 0x07, + 0x04, 0xD5, 0x90, 0xF8, + 0x07, 0x05, 0xC0, 0x07, 0xF4, 0xD1, 0x0E, 0xE0, 0x90, 0xF8, 0x07, 0x05, + 0x80, 0x07, 0x0A, 0xD5, + 0x31, 0x46, 0x05, 0xE0, 0x28, 0x68, 0x90, 0xF8, 0x07, 0x05, 0x40, 0x07, + 0x03, 0xD5, 0x02, 0x21, + 0x68, 0x46, 0x01, 0xF0, 0xC1, 0xFD, 0x68, 0x46, 0xFF, 0xF7, 0xA2, 0xFF, + 0xDD, 0xE9, 0x00, 0x01, + 0xCD, 0xE9, 0x02, 0x01, 0x94, 0xF8, 0x40, 0x00, 0x02, 0x28, 0x41, 0xD1, + 0x28, 0x68, 0x90, 0xF8, + 0x21, 0x03, 0x80, 0x07, 0x3C, 0xD5, 0x02, 0xAB, 0x22, 0x46, 0x41, 0x46, + 0x48, 0x46, 0xFF, 0xF7, + 0xFB, 0xFE, 0x28, 0x68, 0x90, 0xF8, 0x07, 0x05, 0x80, 0x07, 0x03, 0xD5, + 0x31, 0x46, 0x02, 0xA8, + 0x01, 0xF0, 0xA2, 0xFD, 0x02, 0xA8, 0xFF, 0xF7, 0x83, 0xFF, 0x29, 0x68, + 0xE3, 0x69, 0x91, 0xF8, + 0x2D, 0x23, 0x02, 0xF0, 0x0F, 0x00, 0x15, 0x09, 0xB1, 0xF8, 0x2E, 0x23, + 0xB1, 0xF8, 0x30, 0x13, + 0x93, 0x42, 0x0D, 0xDD, 0x8B, 0x42, 0x01, 0xDB, 0x28, 0x46, 0x09, 0xE0, + 0x91, 0x42, 0x00, 0xD1, + 0x49, 0x1C, 0x9B, 0x1A, 0x2D, 0x1A, 0x6B, 0x43, 0x89, 0x1A, 0x93, 0xFB, + 0xF1, 0xF1, 0x08, 0x44, + 0x01, 0x9A, 0x03, 0x9B, 0xC0, 0xF1, 0x10, 0x01, 0x42, 0x43, 0x03, 0xFB, + 0x01, 0x22, 0x12, 0x11, + 0x03, 0x92, 0x00, 0x9A, 0x42, 0x43, 0x02, 0x98, 0x00, 0xFB, 0x01, 0x20, + 0x00, 0x11, 0x02, 0x90, + 0x01, 0x98, 0xE0, 0x81, 0x00, 0x98, 0xA0, 0x81, 0x03, 0x98, 0x60, 0x82, + 0x02, 0x98, 0x20, 0x82, + 0x94, 0xF8, 0x24, 0x00, 0xC0, 0x06, 0x01, 0xD4, 0xE0, 0x68, 0x60, 0x61, + 0xBD, 0xE8, 0xFF, 0x87, + 0x2D, 0xE9, 0xF0, 0x47, 0x05, 0x46, 0x90, 0xF8, 0x02, 0x80, 0x0F, 0x46, + 0x88, 0x68, 0x14, 0x46, + 0x01, 0x26, 0x41, 0x46, 0x09, 0xF0, 0x42, 0xFF, 0x81, 0x46, 0xA8, 0xF1, + 0x01, 0x00, 0xC1, 0xB2, + 0xB8, 0x68, 0x09, 0xF0, 0x3B, 0xFF, 0x29, 0x78, 0x09, 0xEB, 0x41, 0x02, + 0x32, 0xF9, 0x02, 0x2C, + 0xA2, 0x42, 0x03, 0xDB, 0x30, 0xF9, 0x11, 0x10, 0xA1, 0x42, 0x00, 0xDA, + 0x00, 0x26, 0x69, 0x78, + 0x09, 0xEB, 0x41, 0x02, 0xB2, 0xF9, 0x02, 0x20, 0xA2, 0x42, 0x03, 0xDB, + 0x30, 0xF9, 0x11, 0x00, + 0xA0, 0x42, 0x00, 0xDA, 0x00, 0x26, 0x95, 0xF8, 0x03, 0x80, 0xB8, 0x68, + 0x41, 0x46, 0x09, 0xF0, + 0x1D, 0xFF, 0x81, 0x46, 0x08, 0xF1, 0x01, 0x00, 0xC1, 0xB2, 0xB8, 0x68, + 0x09, 0xF0, 0x16, 0xFF, + 0x29, 0x78, 0x09, 0xEB, 0x41, 0x02, 0x32, 0xF9, 0x02, 0x2C, 0xA2, 0x42, + 0x03, 0xDB, 0x30, 0xF9, + 0x11, 0x10, 0xA1, 0x42, 0x00, 0xDA, 0x00, 0x26, 0x69, 0x78, 0x09, 0xEB, + 0x41, 0x02, 0xB2, 0xF9, + 0x02, 0x20, 0xA2, 0x42, 0x03, 0xDB, 0x30, 0xF9, 0x11, 0x00, 0xA0, 0x42, + 0x00, 0xDA, 0x00, 0x26, + 0x30, 0x46, 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xFF, 0x4F, 0x97, 0xB0, + 0x99, 0x46, 0x92, 0x46, + 0xFE, 0x48, 0xDF, 0xF8, 0xFC, 0x83, 0x01, 0x22, 0x04, 0x68, 0x51, 0x46, + 0xD8, 0xF8, 0x00, 0x00, + 0x01, 0xF0, 0x6E, 0xFA, 0xFB, 0x48, 0x00, 0x68, 0xB0, 0xF9, 0x4B, 0x14, + 0x11, 0x91, 0x90, 0xF8, + 0x4A, 0x04, 0x0A, 0x90, 0xF8, 0x48, 0x9A, 0xF8, 0x02, 0x70, 0x9A, 0xF8, + 0x03, 0x60, 0x00, 0x78, + 0x9A, 0xF8, 0x00, 0xB0, 0x9A, 0xF8, 0x01, 0x50, 0x40, 0x1E, 0x87, 0x42, + 0x01, 0xDA, 0x7F, 0x1C, + 0xFF, 0xB2, 0x0E, 0xB1, 0x76, 0x1E, 0xF6, 0xB2, 0xF0, 0x49, 0x09, 0x78, + 0x49, 0x1E, 0x8B, 0x45, + 0x03, 0xDA, 0x0B, 0xF1, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x0B, 0x0D, 0xB1, + 0x6D, 0x1E, 0xED, 0xB2, + 0xB8, 0x1E, 0xC1, 0xB2, 0xD9, 0xF8, 0x08, 0x00, 0x09, 0xF0, 0xC0, 0xFE, + 0x0B, 0x90, 0x78, 0x1E, + 0xC1, 0xB2, 0xD9, 0xF8, 0x08, 0x00, 0x09, 0xF0, 0xB9, 0xFE, 0x04, 0x90, + 0x39, 0x46, 0xD9, 0xF8, + 0x08, 0x00, 0x09, 0xF0, 0xB3, 0xFE, 0x01, 0x90, 0x78, 0x1C, 0xC1, 0xB2, + 0xD9, 0xF8, 0x08, 0x00, + 0x09, 0xF0, 0xAC, 0xFE, 0x02, 0x90, 0xB8, 0x1C, 0xC1, 0xB2, 0xD9, 0xF8, + 0x08, 0x00, 0x09, 0xF0, + 0xA5, 0xFE, 0x03, 0x90, 0x39, 0x46, 0x17, 0x98, 0x09, 0xF0, 0x9A, 0xFE, + 0x08, 0x90, 0xD4, 0x48, + 0x39, 0x46, 0x00, 0x68, 0x09, 0xF0, 0xA2, 0xFE, 0x86, 0x46, 0x00, 0x20, + 0x7A, 0xB2, 0xD4, 0x4F, + 0x0C, 0x90, 0xB7, 0xE0, 0x4F, 0xFA, 0x8B, 0xF0, 0x94, 0xE0, 0x00, 0x21, + 0x0E, 0xF8, 0x00, 0x10, + 0x08, 0x99, 0x18, 0x9B, 0x09, 0x5C, 0x99, 0x42, 0x75, 0xD1, 0xDF, 0xF8, + 0x28, 0xC3, 0x01, 0x9B, + 0xDC, 0xF8, 0x00, 0xC0, 0x33, 0xF9, 0x10, 0x30, 0xBC, 0xF8, 0x4D, 0xC4, + 0x63, 0x45, 0x6A, 0xDA, + 0x00, 0x21, 0x14, 0x91, 0x13, 0x91, 0x11, 0x99, 0x19, 0x44, 0x04, 0x9B, + 0x09, 0xB2, 0x33, 0xF9, + 0x10, 0x30, 0x10, 0x93, 0x8B, 0x42, 0x06, 0xDD, 0x02, 0x9B, 0x33, 0xF9, + 0x10, 0x30, 0x8B, 0x42, + 0x01, 0xDD, 0x01, 0x23, 0x13, 0x93, 0x01, 0x9B, 0x03, 0xEB, 0x40, 0x03, + 0x33, 0xF9, 0x02, 0x8C, + 0x88, 0x45, 0x07, 0xDD, 0xB3, 0xF9, 0x02, 0xC0, 0x8C, 0x45, 0x03, 0xDD, + 0x4F, 0xF0, 0x01, 0x0C, + 0xCD, 0xF8, 0x50, 0xC0, 0x01, 0x2A, 0x0F, 0xDD, 0xDD, 0xF8, 0x2C, 0xC0, + 0x3C, 0xF9, 0x10, 0xC0, + 0x8C, 0x45, 0x09, 0xDD, 0xDD, 0xF8, 0x08, 0xC0, 0x3C, 0xF9, 0x10, 0xC0, + 0x8C, 0x45, 0x03, 0xDD, + 0x4F, 0xF0, 0x01, 0x0C, 0xCD, 0xF8, 0x4C, 0xC0, 0xDF, 0xF8, 0xAC, 0xC2, + 0x9C, 0xF8, 0x00, 0xC0, + 0xAC, 0xF1, 0x02, 0x0C, 0x62, 0x45, 0x0D, 0xDA, 0xDD, 0xF8, 0x40, 0xC0, + 0x8C, 0x45, 0x09, 0xDD, + 0xDD, 0xF8, 0x0C, 0xC0, 0x3C, 0xF9, 0x10, 0xC0, 0x8C, 0x45, 0x03, 0xDD, + 0x4F, 0xF0, 0x01, 0x0C, + 0xCD, 0xF8, 0x4C, 0xC0, 0x01, 0x28, 0x0B, 0xDD, 0x33, 0xF9, 0x04, 0xCC, + 0x8C, 0x45, 0x07, 0xDD, + 0xB3, 0xF9, 0x02, 0xC0, 0x8C, 0x45, 0x03, 0xDD, 0x4F, 0xF0, 0x01, 0x0C, + 0xCD, 0xF8, 0x50, 0xC0, + 0xDF, 0xF8, 0x68, 0xC2, 0x9C, 0xF8, 0x00, 0xC0, 0xAC, 0xF1, 0x02, 0x0C, + 0x60, 0x45, 0x05, 0xDA, + 0x88, 0x45, 0x03, 0xDD, 0xB3, 0xF9, 0x04, 0x30, 0x8B, 0x42, 0x12, 0xDC, + 0x14, 0x99, 0x81, 0xB9, + 0x13, 0x99, 0x0D, 0xE0, 0xFF, 0xE7, 0x99, 0xB9, 0x01, 0x99, 0xB7, 0xF9, + 0x00, 0x30, 0x31, 0xF9, + 0x10, 0x10, 0x99, 0x42, 0x0C, 0xDA, 0x8B, 0x49, 0x09, 0x68, 0x91, 0xF8, + 0x41, 0x14, 0xC9, 0x07, + 0x31, 0xB1, 0x01, 0x21, 0x0E, 0xF8, 0x00, 0x10, 0x0C, 0x99, 0x49, 0x1C, + 0x89, 0xB2, 0x0C, 0x91, + 0x40, 0x1C, 0x40, 0xB2, 0xA8, 0x42, 0x7F, 0xF7, 0x68, 0xAF, 0x84, 0x48, + 0x0B, 0x99, 0x0E, 0xF1, + 0x28, 0x0E, 0x00, 0x78, 0x01, 0xEB, 0x40, 0x01, 0x0B, 0x91, 0x04, 0x99, + 0x01, 0xEB, 0x40, 0x01, + 0x04, 0x91, 0x01, 0x99, 0x01, 0xEB, 0x40, 0x01, 0x01, 0x91, 0x02, 0x99, + 0x01, 0xEB, 0x40, 0x01, + 0x02, 0x91, 0x03, 0x99, 0x01, 0xEB, 0x40, 0x00, 0x03, 0x90, 0x08, 0x98, + 0x28, 0x30, 0x52, 0x1C, + 0x52, 0xB2, 0x08, 0x90, 0xB2, 0x42, 0x7F, 0xF7, 0x45, 0xAF, 0x0A, 0x99, + 0x0C, 0x98, 0x88, 0x42, + 0x2A, 0xD9, 0x00, 0x20, 0x84, 0xF8, 0x0E, 0x01, 0xDA, 0xF8, 0x00, 0x00, + 0x20, 0x60, 0x6C, 0x48, + 0x00, 0x23, 0x1A, 0x46, 0x21, 0x46, 0x00, 0x68, 0x01, 0xF0, 0x22, 0xFA, + 0x01, 0x25, 0x17, 0xE0, + 0x04, 0xEB, 0x85, 0x00, 0x06, 0x46, 0x51, 0x46, 0x00, 0xF0, 0x53, 0xF9, + 0x70, 0xB1, 0x04, 0xEB, + 0x45, 0x00, 0xB0, 0xF8, 0xB4, 0x10, 0x0A, 0x98, 0x81, 0x42, 0x07, 0xD9, + 0x30, 0x46, 0xB7, 0xF9, + 0x00, 0x20, 0x49, 0x46, 0xFF, 0xF7, 0x64, 0xFE, 0x01, 0x28, 0x06, 0xD0, + 0x6D, 0x1C, 0xED, 0xB2, + 0x94, 0xF8, 0x0E, 0x01, 0xA8, 0x42, 0xE3, 0xD2, 0x00, 0x20, 0x1B, 0xB0, + 0xBD, 0xE8, 0xF0, 0x8F, + 0x2D, 0xE9, 0xF8, 0x4F, 0x04, 0x46, 0x55, 0x48, 0xDF, 0xF8, 0x54, 0x81, + 0x91, 0x46, 0x8B, 0x46, + 0x05, 0x68, 0x01, 0x22, 0x21, 0x46, 0xD8, 0xF8, 0x00, 0x00, 0x01, 0xF0, + 0x19, 0xF9, 0x00, 0x27, + 0xA6, 0x78, 0x4F, 0xF0, 0x01, 0x0A, 0x1D, 0xE0, 0x31, 0x46, 0xD8, 0xF8, + 0x00, 0x00, 0x09, 0xF0, + 0x95, 0xFD, 0x00, 0x90, 0x31, 0x46, 0xDB, 0xF8, 0x08, 0x00, 0x09, 0xF0, + 0x87, 0xFD, 0x01, 0x46, + 0x20, 0x78, 0x52, 0x46, 0x09, 0xE0, 0x00, 0xBF, 0x31, 0xF9, 0x10, 0xC0, + 0xCC, 0x45, 0x02, 0xDA, + 0x00, 0x9B, 0x01, 0x27, 0x1A, 0x54, 0x40, 0x1C, 0xC0, 0xB2, 0x63, 0x78, + 0x83, 0x42, 0xF3, 0xD2, + 0x76, 0x1C, 0xF6, 0xB2, 0xE0, 0x78, 0xB0, 0x42, 0xDE, 0xD2, 0x01, 0x2F, + 0x2E, 0xD1, 0x00, 0x20, + 0x85, 0xF8, 0x0E, 0x01, 0x20, 0x68, 0x28, 0x60, 0x00, 0x23, 0x1A, 0x46, + 0x29, 0x46, 0xD8, 0xF8, + 0x00, 0x00, 0x01, 0xF0, 0xBD, 0xF9, 0x01, 0x26, 0xDF, 0xF8, 0xD8, 0x80, + 0x1A, 0xE0, 0x00, 0xBF, + 0x05, 0xEB, 0x86, 0x07, 0x21, 0x46, 0x38, 0x46, 0x00, 0xF0, 0xEB, 0xF8, + 0x80, 0xB1, 0x05, 0xEB, + 0x46, 0x00, 0xB0, 0xF8, 0xB4, 0x10, 0xD8, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0x4A, 0x04, 0x81, 0x42, + 0x06, 0xD9, 0x38, 0x46, 0x4A, 0x46, 0x59, 0x46, 0xFF, 0xF7, 0xFA, 0xFD, + 0x01, 0x28, 0x06, 0xD0, + 0x76, 0x1C, 0xF6, 0xB2, 0x95, 0xF8, 0x0E, 0x01, 0xB0, 0x42, 0xE1, 0xD2, + 0x00, 0x20, 0xBD, 0xE8, + 0xF8, 0x8F, 0x2D, 0xE9, 0xF0, 0x41, 0x23, 0x4D, 0x0F, 0x46, 0x80, 0x46, + 0x29, 0x68, 0x14, 0x46, + 0x24, 0x48, 0x1E, 0x46, 0x9A, 0x69, 0xB1, 0xF8, 0x47, 0x34, 0x00, 0x78, + 0x9A, 0x42, 0x10, 0xDC, + 0xF2, 0x8C, 0x04, 0x2A, 0x0D, 0xD9, 0x62, 0x78, 0x23, 0x78, 0x91, 0xF8, + 0x49, 0x14, 0xD2, 0x1A, + 0x52, 0x1C, 0x8A, 0x42, 0x05, 0xDC, 0xE2, 0x78, 0xA3, 0x78, 0xD2, 0x1A, + 0x52, 0x1C, 0x8A, 0x42, + 0x02, 0xDD, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x28, 0xFB, 0xD1, + 0x14, 0x48, 0x31, 0x46, + 0xB0, 0xF9, 0x00, 0x20, 0x20, 0x46, 0xFF, 0xF7, 0x6B, 0xFF, 0x00, 0x28, + 0xF2, 0xD1, 0x29, 0x68, + 0x91, 0xF8, 0x40, 0x24, 0x92, 0x07, 0xED, 0xD5, 0x91, 0xF8, 0xE0, 0x22, + 0x52, 0x06, 0x09, 0xD5, + 0x0D, 0x4A, 0x52, 0x78, 0x02, 0xB3, 0xB1, 0xF8, 0xF0, 0x12, 0x0C, 0x4A, + 0x49, 0x43, 0x12, 0x68, + 0x8A, 0x42, 0xDF, 0xDC, 0x33, 0x46, 0x22, 0x46, 0x39, 0x46, 0x11, 0xE0, + 0x6C, 0x06, 0x10, 0x00, + 0x54, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xED, 0x06, 0x10, 0x00, + 0xEE, 0x06, 0x10, 0x00, + 0xA8, 0x06, 0x10, 0x00, 0x34, 0x06, 0x10, 0x00, 0x74, 0x07, 0x10, 0x00, + 0x24, 0x07, 0x10, 0x00, + 0x40, 0x46, 0xBD, 0xE8, 0xF0, 0x41, 0xE6, 0xE5, 0xB1, 0xF8, 0xEE, 0x12, + 0xDD, 0xE7, 0x2D, 0xE9, + 0xFF, 0x4F, 0x81, 0xB0, 0xDF, 0xF8, 0x04, 0xB1, 0xDD, 0xF8, 0x38, 0x90, + 0x5F, 0xEA, 0x03, 0x08, + 0x15, 0x46, 0x1C, 0xD4, 0x2C, 0x78, 0x0B, 0xEB, 0xC8, 0x0A, 0x15, 0xE0, + 0x08, 0xF0, 0xFF, 0x01, + 0x01, 0x98, 0x09, 0xF0, 0xD3, 0xFC, 0x00, 0x90, 0xDA, 0xE9, 0x00, 0x67, + 0x22, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x09, 0xF0, 0x03, 0xFB, 0x06, 0x40, 0x0F, 0x40, 0x3E, 0x43, + 0x02, 0xD1, 0x00, 0x98, + 0x00, 0x21, 0x01, 0x55, 0x64, 0x1C, 0xE4, 0xB2, 0x68, 0x78, 0xA0, 0x42, + 0xE6, 0xD2, 0xB9, 0xF1, + 0x00, 0x00, 0x1E, 0xDB, 0x02, 0x46, 0xAC, 0x78, 0x01, 0x20, 0x00, 0x21, + 0x09, 0xF0, 0xEE, 0xFA, + 0x06, 0x46, 0x0F, 0x46, 0x4F, 0xF0, 0x00, 0x08, 0x10, 0xE0, 0x21, 0x46, + 0x01, 0x98, 0x09, 0xF0, + 0xAD, 0xFC, 0x0B, 0xEB, 0xC4, 0x01, 0x02, 0x46, 0xD1, 0xE9, 0x00, 0x01, + 0x30, 0x40, 0x39, 0x40, + 0x08, 0x43, 0x01, 0xD1, 0x02, 0xF8, 0x09, 0x80, 0x64, 0x1C, 0xE4, 0xB2, + 0xE8, 0x78, 0xA0, 0x42, + 0xEB, 0xD2, 0x05, 0xB0, 0xEA, 0xE6, 0x70, 0xB5, 0x1E, 0x4B, 0x1D, 0x4A, + 0x8C, 0x69, 0x1B, 0x68, + 0x12, 0x78, 0xB3, 0xF8, 0x47, 0x54, 0xAC, 0x42, 0x10, 0xDC, 0xCC, 0x8C, + 0x04, 0x2C, 0x0D, 0xD9, + 0x44, 0x78, 0x05, 0x78, 0x93, 0xF8, 0x49, 0x34, 0x64, 0x1B, 0x64, 0x1C, + 0x9C, 0x42, 0x05, 0xDC, + 0xC4, 0x78, 0x85, 0x78, 0x64, 0x1B, 0x64, 0x1C, 0x9C, 0x42, 0x01, 0xDD, + 0x00, 0x22, 0x06, 0xE0, + 0x2A, 0xB9, 0x11, 0x4A, 0xB2, 0xF9, 0x00, 0x20, 0xFF, 0xF7, 0xCA, 0xFE, + 0x02, 0x46, 0x10, 0x46, + 0x70, 0xBD, 0x02, 0x78, 0x0B, 0x78, 0x9A, 0x42, 0x0B, 0xD9, 0x42, 0x78, + 0x4B, 0x78, 0x9A, 0x42, + 0x07, 0xD2, 0x82, 0x78, 0x8B, 0x78, 0x9A, 0x42, 0x03, 0xD9, 0xC0, 0x78, + 0xC9, 0x78, 0x88, 0x42, + 0x01, 0xD3, 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x98, 0x46, 0x10, 0x00, + 0x34, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x92, 0x06, 0x10, 0x00, + 0x70, 0xB5, 0xFE, 0x4C, + 0x00, 0xEB, 0x43, 0x05, 0x04, 0x9E, 0x00, 0xEB, 0x83, 0x03, 0x86, 0xB1, + 0x8E, 0x69, 0xA6, 0x60, + 0xCE, 0x8C, 0x66, 0x80, 0x09, 0x68, 0x61, 0x61, 0xB5, 0xF8, 0xB4, 0x10, + 0xA1, 0x80, 0x19, 0x68, + 0xE1, 0x60, 0x90, 0xF8, 0x0E, 0x01, 0x20, 0x70, 0x10, 0x68, 0x20, 0x61, + 0x70, 0xBD, 0xA6, 0x68, + 0x8E, 0x61, 0x66, 0x88, 0xCE, 0x84, 0x66, 0x69, 0x0E, 0x60, 0xA1, 0x88, + 0xA5, 0xF8, 0xB4, 0x10, + 0xE1, 0x68, 0x19, 0x60, 0x21, 0x78, 0x80, 0xF8, 0x0E, 0x11, 0x20, 0x69, + 0x10, 0x60, 0x70, 0xBD, + 0x2D, 0xE9, 0xF0, 0x47, 0xE9, 0x4D, 0x81, 0x46, 0xE9, 0x4F, 0x28, 0x68, + 0x1C, 0x46, 0x16, 0x46, + 0x90, 0xF8, 0x30, 0x02, 0x88, 0x46, 0x00, 0x07, 0x07, 0xD5, 0x38, 0x78, + 0x01, 0x28, 0x04, 0xD0, + 0x48, 0x46, 0xF9, 0xF7, 0xAF, 0xF8, 0x00, 0x28, 0x40, 0xD0, 0x28, 0x68, + 0x90, 0xF8, 0x30, 0x02, + 0x00, 0x06, 0x0A, 0xD5, 0x38, 0x78, 0x01, 0x28, 0x07, 0xD0, 0xDE, 0x48, + 0x00, 0x78, 0x20, 0xB1, + 0x30, 0x46, 0xF9, 0xF7, 0xF1, 0xF8, 0x00, 0x28, 0x30, 0xD0, 0xDB, 0x4B, + 0x32, 0x46, 0x41, 0x46, + 0x48, 0x46, 0x00, 0xF0, 0x34, 0xFF, 0x00, 0x28, 0x28, 0xD0, 0x94, 0xF8, + 0x40, 0x00, 0x03, 0x28, + 0x08, 0xD1, 0x29, 0x68, 0xE0, 0x8C, 0x91, 0xF8, 0x07, 0x13, 0x88, 0x42, + 0x02, 0xD9, 0x04, 0x20, + 0x84, 0xF8, 0x40, 0x00, 0x30, 0x68, 0xC4, 0xF8, 0x36, 0x00, 0x04, 0xF1, + 0x44, 0x02, 0x51, 0x1E, + 0x30, 0x46, 0xF8, 0xF7, 0xBE, 0xF9, 0x22, 0x46, 0x31, 0x46, 0xCB, 0x48, + 0x00, 0xF0, 0x7A, 0xFD, + 0x31, 0x46, 0xC9, 0x48, 0x00, 0xF0, 0xAC, 0xFE, 0x22, 0x46, 0x31, 0x46, + 0xC6, 0x48, 0xFF, 0xF7, + 0xE6, 0xFB, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x47, 0xFE, 0xF7, 0xD7, 0xB9, + 0xBD, 0xE8, 0xF0, 0x87, + 0x2D, 0xE9, 0xF0, 0x41, 0x0D, 0x46, 0x1F, 0x46, 0x16, 0x46, 0x04, 0x46, + 0x48, 0x21, 0x09, 0xF0, + 0xDD, 0xFA, 0x00, 0x20, 0x84, 0xF8, 0x40, 0x00, 0xBC, 0x48, 0x00, 0x68, + 0x60, 0x60, 0xA0, 0x60, + 0x06, 0xEB, 0x45, 0x00, 0x84, 0xF8, 0x42, 0x50, 0x30, 0xF8, 0xB4, 0x1F, + 0x61, 0x85, 0x00, 0x88, + 0xE0, 0x84, 0x06, 0xEB, 0x85, 0x00, 0x00, 0x68, 0xC4, 0xF8, 0x3A, 0x00, + 0xAE, 0x48, 0x81, 0x69, + 0x21, 0x60, 0x01, 0x21, 0xA9, 0x40, 0x39, 0x42, 0x01, 0xD0, 0x40, 0x6A, + 0x20, 0x60, 0xBD, 0xE8, + 0xF0, 0x81, 0x2D, 0xE9, 0xF0, 0x47, 0x89, 0x46, 0x1C, 0x46, 0x16, 0x46, + 0xAC, 0x4D, 0x03, 0xF1, + 0x3E, 0x08, 0x91, 0x78, 0x09, 0xF0, 0x94, 0xFB, 0x07, 0x46, 0xB1, 0x78, + 0x60, 0x68, 0x09, 0xF0, + 0x95, 0xFB, 0x02, 0x46, 0x00, 0x20, 0xA0, 0x61, 0xB1, 0x78, 0x1F, 0xE0, + 0x30, 0x78, 0x13, 0xE0, + 0x17, 0xF8, 0x00, 0xC0, 0xCC, 0x45, 0x0D, 0xD1, 0x32, 0xF9, 0x10, 0x30, + 0xD4, 0xF8, 0x18, 0xC0, + 0xAB, 0x42, 0x9C, 0x44, 0xC4, 0xF8, 0x18, 0xC0, 0x04, 0xDD, 0x88, 0xF8, + 0x00, 0x00, 0x1D, 0x46, + 0x88, 0xF8, 0x01, 0x10, 0x40, 0x1C, 0xC0, 0xB2, 0x73, 0x78, 0x83, 0x42, + 0xE8, 0xD2, 0x99, 0x48, + 0x49, 0x1C, 0xC9, 0xB2, 0x00, 0x78, 0x28, 0x37, 0x02, 0xEB, 0x40, 0x02, + 0xF0, 0x78, 0x88, 0x42, + 0xDC, 0xD2, 0x65, 0x86, 0x9A, 0xE7, 0x2D, 0xE9, 0xFF, 0x4F, 0x81, 0xB0, + 0x0C, 0x46, 0x1E, 0x46, + 0x99, 0x78, 0xDD, 0xF8, 0x40, 0x80, 0x0E, 0x9D, 0x09, 0xF0, 0x68, 0xFB, + 0x00, 0x90, 0xB1, 0x78, + 0x20, 0x46, 0x09, 0xF0, 0x55, 0xFB, 0x83, 0x46, 0xB1, 0x78, 0xD8, 0xF8, + 0x04, 0x00, 0x09, 0xF0, + 0x55, 0xFB, 0x81, 0x46, 0x88, 0x48, 0x4F, 0xF0, 0x00, 0x0A, 0xC8, 0xF8, + 0x18, 0xA0, 0x00, 0x68, + 0x28, 0x60, 0xB7, 0x78, 0x42, 0xE0, 0x34, 0x78, 0x32, 0xE0, 0x00, 0xBF, + 0x1B, 0xF8, 0x04, 0x10, + 0x03, 0x98, 0x81, 0x42, 0x2A, 0xD1, 0x39, 0xF9, 0x14, 0x10, 0x0F, 0x98, + 0x81, 0x42, 0x22, 0xDD, + 0x00, 0x99, 0x03, 0x98, 0x08, 0x55, 0x29, 0x78, 0x20, 0x46, 0x05, 0xF0, + 0x35, 0xFA, 0x28, 0x70, + 0x69, 0x78, 0x20, 0x46, 0x05, 0xF0, 0x34, 0xFA, 0x68, 0x70, 0xA9, 0x78, + 0x38, 0x46, 0x05, 0xF0, + 0x2B, 0xFA, 0xA8, 0x70, 0xE9, 0x78, 0x38, 0x46, 0x05, 0xF0, 0x2A, 0xFA, + 0xE8, 0x70, 0x0A, 0xF1, + 0x01, 0x00, 0x1F, 0xFA, 0x80, 0xFA, 0x39, 0xF9, 0x14, 0x00, 0xD8, 0xF8, + 0x18, 0x10, 0x01, 0x44, + 0xC8, 0xF8, 0x18, 0x10, 0x02, 0xE0, 0x00, 0x99, 0x00, 0x20, 0x08, 0x55, + 0x64, 0x1C, 0xE4, 0xB2, + 0x70, 0x78, 0xA0, 0x42, 0xCA, 0xD2, 0x00, 0x98, 0x66, 0x49, 0x28, 0x30, + 0x00, 0x90, 0x09, 0x78, + 0x7F, 0x1C, 0x0B, 0xF1, 0x28, 0x0B, 0x09, 0xEB, 0x41, 0x09, 0xFF, 0xB2, + 0xF0, 0x78, 0xB8, 0x42, + 0xB9, 0xD2, 0xA8, 0xF8, 0x26, 0xA0, 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x2D, 0xE9, 0xFF, 0x41, + 0x17, 0x46, 0x0A, 0xAA, 0x80, 0x46, 0x92, 0xE8, 0x31, 0x00, 0x5C, 0x4A, + 0x1E, 0x46, 0xB2, 0xF9, + 0x00, 0x20, 0x82, 0x42, 0x02, 0xDB, 0x00, 0x20, 0x04, 0xB0, 0x48, 0xE7, + 0x03, 0xAA, 0xCD, 0xE9, + 0x00, 0x20, 0x02, 0x94, 0x3A, 0x46, 0x40, 0x46, 0xFF, 0xF7, 0x7D, 0xFF, + 0x01, 0x21, 0x28, 0x68, + 0xB9, 0x40, 0x08, 0x43, 0x28, 0x60, 0xC4, 0xF8, 0x00, 0x80, 0xE0, 0x8C, + 0x10, 0xB1, 0x03, 0x98, + 0x30, 0x60, 0xE8, 0xE7, 0x01, 0x20, 0xE7, 0xE7, 0x2D, 0xE9, 0xFF, 0x4F, + 0x81, 0xB0, 0x90, 0x46, + 0x0E, 0x9C, 0x8B, 0x46, 0x04, 0xEB, 0x88, 0x00, 0x94, 0xF8, 0x0E, 0x71, + 0xDD, 0xF8, 0x40, 0xA0, + 0x00, 0x68, 0x1E, 0x46, 0x20, 0x60, 0x01, 0x23, 0x21, 0x46, 0x58, 0x46, + 0x00, 0xF0, 0x20, 0xFF, + 0x01, 0x98, 0x58, 0x45, 0x1F, 0xD0, 0xB5, 0x78, 0x1A, 0xE0, 0x29, 0x46, + 0x01, 0x98, 0x09, 0xF0, + 0xC5, 0xFA, 0x81, 0x46, 0x29, 0x46, 0x58, 0x46, 0x09, 0xF0, 0xC0, 0xFA, + 0x01, 0x46, 0x30, 0x78, + 0x09, 0xE0, 0x00, 0xBF, 0x19, 0xF8, 0x00, 0x30, 0x43, 0x45, 0x02, 0xD1, + 0x0B, 0x5C, 0x09, 0xF8, + 0x00, 0x30, 0x40, 0x1C, 0xC0, 0xB2, 0x72, 0x78, 0x82, 0x42, 0xF3, 0xD2, + 0x6D, 0x1C, 0xED, 0xB2, + 0xF0, 0x78, 0xA8, 0x42, 0xE1, 0xD2, 0x94, 0xF8, 0x0E, 0x01, 0x00, 0x25, + 0x01, 0x21, 0xB8, 0x42, + 0x12, 0xD0, 0x11, 0x98, 0x78, 0xB1, 0x7F, 0x1C, 0xF8, 0xB2, 0x08, 0xE0, + 0xDA, 0xF8, 0x00, 0x20, + 0x01, 0xFA, 0x00, 0xF3, 0x1A, 0x43, 0x40, 0x1C, 0xC0, 0xB2, 0xCA, 0xF8, + 0x00, 0x20, 0x94, 0xF8, + 0x0E, 0x21, 0x82, 0x42, 0xF2, 0xD2, 0x01, 0x25, 0x00, 0x91, 0x43, 0x46, + 0x52, 0x46, 0x20, 0x46, + 0x0F, 0x99, 0xFF, 0xF7, 0x33, 0xFE, 0x28, 0x46, 0x7D, 0xE7, 0x10, 0xB5, + 0x17, 0x4A, 0x20, 0x4C, + 0x13, 0x68, 0x64, 0x78, 0x93, 0xF8, 0x06, 0x23, 0x4C, 0xB1, 0x91, 0xF8, + 0x24, 0x10, 0x09, 0x07, + 0x02, 0xD5, 0x93, 0xF8, 0x09, 0x13, 0x01, 0xE0, 0x93, 0xF8, 0x08, 0x13, + 0x0A, 0x44, 0x90, 0x42, + 0x01, 0xD9, 0x01, 0x20, 0x10, 0xBD, 0x00, 0x20, 0x10, 0xBD, 0x2D, 0xE9, + 0xF0, 0x47, 0x1C, 0x46, + 0x17, 0x46, 0x88, 0x46, 0x81, 0x46, 0x01, 0xF0, 0xED, 0xF8, 0x08, 0x4E, + 0xE1, 0x8C, 0x30, 0x68, + 0x90, 0xF8, 0x0E, 0x23, 0x91, 0x42, 0x7C, 0xD8, 0x03, 0x21, 0x84, 0xF8, + 0x40, 0x10, 0x90, 0xF8, + 0xE0, 0x12, 0x00, 0x25, 0x8A, 0x07, 0x15, 0xE0, 0x38, 0x06, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0x66, 0x05, 0x10, 0x00, 0xF4, 0x06, 0x10, 0x00, 0xF0, 0x45, 0x10, 0x00, + 0x10, 0x07, 0x10, 0x00, + 0x00, 0x80, 0xFF, 0xFF, 0xEE, 0x06, 0x10, 0x00, 0x36, 0x7A, 0x01, 0x00, + 0x9A, 0x06, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, 0x01, 0xD4, 0x49, 0x07, 0x00, 0xD5, 0x01, 0x25, + 0xFF, 0x4A, 0xB0, 0xF8, + 0x0A, 0x13, 0x52, 0x78, 0x22, 0xB1, 0xFE, 0x4A, 0x12, 0x78, 0x0A, 0xB9, + 0xB0, 0xF8, 0x0C, 0x13, + 0xA2, 0x8D, 0x8A, 0x42, 0x02, 0xD2, 0xFB, 0x49, 0x09, 0x78, 0x21, 0xB1, + 0x61, 0x8D, 0x03, 0x29, + 0x06, 0xD2, 0x00, 0x25, 0x2C, 0xE0, 0x61, 0x8D, 0x00, 0x25, 0x03, 0x29, + 0xF9, 0xD3, 0x27, 0xE0, + 0x35, 0xB3, 0x90, 0xF8, 0x40, 0x04, 0xC1, 0x07, 0x0D, 0xD0, 0x40, 0x07, + 0x0B, 0xD5, 0x21, 0x46, + 0x38, 0x46, 0xFF, 0xF7, 0x80, 0xFD, 0xF0, 0x49, 0x08, 0x70, 0x20, 0xB1, + 0xA0, 0x8C, 0x40, 0xF0, + 0x80, 0x00, 0xA0, 0x84, 0xE5, 0xE7, 0x30, 0x68, 0x90, 0xF8, 0x20, 0x04, + 0xC0, 0x07, 0x0F, 0xD0, + 0xEA, 0x48, 0xEB, 0x49, 0xB0, 0xF9, 0x00, 0x00, 0xB1, 0xF9, 0x00, 0x10, + 0x88, 0x42, 0x07, 0xDB, + 0x23, 0x46, 0x3A, 0x46, 0x41, 0x46, 0x48, 0x46, 0x02, 0xF0, 0x4D, 0xF9, + 0x01, 0x28, 0x04, 0xD0, + 0xA0, 0x8C, 0x10, 0xF4, 0xC0, 0x7F, 0x19, 0xD1, 0x04, 0xE0, 0xA0, 0x8C, + 0x40, 0xF4, 0x80, 0x70, + 0xA0, 0x84, 0x13, 0xE0, 0x95, 0xB1, 0x30, 0x68, 0x90, 0xF8, 0xE0, 0x02, + 0xC0, 0x07, 0x03, 0xD0, + 0x21, 0x46, 0x38, 0x46, 0x01, 0xF0, 0x3B, 0xFA, 0x23, 0x46, 0x3A, 0x46, + 0x41, 0x46, 0x48, 0x46, + 0x00, 0xE0, 0x0A, 0xE0, 0xBD, 0xE8, 0xF0, 0x47, 0x01, 0xF0, 0xFD, 0xBF, + 0x23, 0x46, 0x3A, 0x46, + 0x41, 0x46, 0x48, 0x46, 0xBD, 0xE8, 0xF0, 0x47, 0xAA, 0xE5, 0x04, 0x20, + 0x84, 0xF8, 0x40, 0x00, + 0xF4, 0xE7, 0xD0, 0x48, 0x00, 0x78, 0x80, 0x07, 0x0B, 0xD5, 0xCF, 0x48, + 0xCF, 0x4A, 0x00, 0x68, + 0x12, 0x68, 0x90, 0xF8, 0x57, 0x13, 0x91, 0x42, 0x05, 0xD2, 0x90, 0xF8, + 0x40, 0x03, 0x80, 0x07, + 0x01, 0xD5, 0x00, 0x20, 0x70, 0x47, 0x01, 0x20, 0x70, 0x47, 0x91, 0xF8, + 0x24, 0x10, 0xC6, 0x4A, + 0xCB, 0x07, 0xC7, 0x49, 0x12, 0x68, 0x09, 0x78, 0x06, 0xD0, 0x11, 0xB1, + 0x92, 0xF8, 0x48, 0x13, + 0x05, 0xE0, 0x92, 0xF8, 0x49, 0x13, 0x02, 0xE0, 0x59, 0xB1, 0x92, 0xF8, + 0x46, 0x13, 0xB7, 0x4B, + 0x5B, 0x78, 0x13, 0xB1, 0x92, 0xF8, 0x4A, 0x23, 0x11, 0x44, 0x88, 0x42, + 0x04, 0xD9, 0x01, 0x20, + 0x70, 0x47, 0x92, 0xF8, 0x47, 0x13, 0xF2, 0xE7, 0x00, 0x20, 0x70, 0x47, + 0x2D, 0xE9, 0xFF, 0x4F, + 0xB8, 0x48, 0xDF, 0xF8, 0xD4, 0x92, 0x87, 0xB0, 0xB0, 0xF9, 0x00, 0x80, + 0xD9, 0xF8, 0x00, 0x00, + 0x0C, 0x46, 0x00, 0x26, 0x90, 0xF8, 0x40, 0x04, 0xDF, 0xF8, 0xCC, 0xB2, + 0xC1, 0x07, 0x14, 0x98, + 0x4F, 0xF0, 0x01, 0x07, 0x15, 0x46, 0x07, 0xFA, 0x00, 0xF7, 0xB2, 0x46, + 0x3A, 0xD0, 0xAF, 0x49, + 0xA7, 0x4A, 0xB1, 0xF9, 0x00, 0x00, 0xB2, 0xF9, 0x00, 0x20, 0x90, 0x42, + 0x32, 0xDA, 0x2A, 0x68, + 0x3A, 0x42, 0x2F, 0xD1, 0xE2, 0x8C, 0x04, 0x2A, 0x2C, 0xD9, 0x8D, 0xE8, + 0x31, 0x00, 0x0A, 0x9B, + 0x14, 0x9A, 0xDB, 0xF8, 0x18, 0x10, 0xDB, 0xF8, 0x24, 0x00, 0xFF, 0xF7, + 0x67, 0xFE, 0x06, 0x00, + 0x20, 0xD1, 0x23, 0x46, 0x20, 0x68, 0x0A, 0x9A, 0x14, 0x99, 0xFF, 0xF7, + 0x22, 0xFC, 0x96, 0x49, + 0x08, 0x70, 0xA0, 0xB1, 0x70, 0x1E, 0x8D, 0xF8, 0x10, 0x00, 0x8D, 0xF8, + 0x14, 0x00, 0xD9, 0xF8, + 0x00, 0x00, 0x90, 0xF8, 0x41, 0x04, 0x80, 0x07, 0x05, 0xD5, 0x05, 0xAA, + 0x04, 0xA9, 0x0A, 0x98, + 0xF7, 0xF7, 0x93, 0xFF, 0xA8, 0xB3, 0xA0, 0x8C, 0x40, 0xF0, 0x80, 0x00, + 0xA0, 0x84, 0x93, 0x48, + 0xB0, 0xF9, 0x00, 0x80, 0xD9, 0xF8, 0x00, 0x00, 0x90, 0xF8, 0x20, 0x04, + 0xC0, 0x07, 0x53, 0xD0, + 0x94, 0xF8, 0x24, 0x00, 0x00, 0x06, 0x4F, 0xD4, 0x84, 0x48, 0x85, 0x4A, + 0xB0, 0xF9, 0x00, 0x10, + 0xB2, 0xF9, 0x00, 0x20, 0x91, 0x42, 0x47, 0xDA, 0x81, 0x46, 0x41, 0x45, + 0x17, 0xD0, 0x28, 0x68, + 0x38, 0x42, 0x07, 0xD0, 0xCD, 0xF8, 0x00, 0xA0, 0x2A, 0x46, 0x21, 0x46, + 0x14, 0x9B, 0x07, 0x98, + 0xFF, 0xF7, 0xD4, 0xFC, 0xB9, 0xF9, 0x00, 0x00, 0x8D, 0xE8, 0x31, 0x00, + 0x0A, 0x9B, 0x14, 0x9A, + 0xDB, 0xF8, 0x18, 0x10, 0xDB, 0xF8, 0x24, 0x00, 0xFF, 0xF7, 0x18, 0xFE, + 0x06, 0x46, 0xFE, 0xB1, + 0x2A, 0xE0, 0xFF, 0xE7, 0x7A, 0x49, 0x9D, 0xF9, 0x10, 0x30, 0x01, 0xF8, + 0x36, 0x3F, 0x9D, 0xF9, + 0x14, 0x00, 0x48, 0x70, 0x00, 0x90, 0x20, 0x68, 0x0A, 0x9A, 0x07, 0x99, + 0xFF, 0xF7, 0x27, 0xFC, + 0x07, 0x98, 0x04, 0xF1, 0x3A, 0x03, 0x8D, 0xE8, 0x31, 0x04, 0x21, 0x68, + 0x14, 0x9A, 0xDB, 0xF8, + 0x18, 0x00, 0xFF, 0xF7, 0x21, 0xFE, 0x00, 0x28, 0xB1, 0xD0, 0x01, 0x20, + 0x0B, 0xB0, 0xF3, 0xE5, + 0x23, 0x46, 0x20, 0x68, 0x0A, 0x9A, 0x14, 0x99, 0x02, 0xF0, 0x45, 0xF8, + 0x01, 0x28, 0x03, 0xD1, + 0xA0, 0x8C, 0x40, 0xF4, 0x80, 0x70, 0xA0, 0x84, 0xA0, 0x8C, 0x10, 0xF4, + 0xC0, 0x7F, 0x0A, 0xD1, + 0x28, 0x68, 0x38, 0x42, 0x07, 0xD0, 0xCD, 0xF8, 0x00, 0xA0, 0x2A, 0x46, + 0x21, 0x46, 0x14, 0x9B, + 0x07, 0x98, 0xFF, 0xF7, 0x8B, 0xFC, 0x30, 0x46, 0xE0, 0xE7, 0x2D, 0xE9, + 0xF0, 0x4F, 0x5D, 0x49, + 0x53, 0x48, 0xE7, 0xB0, 0xB1, 0xF9, 0x00, 0x10, 0xB0, 0xF9, 0x00, 0x00, + 0x4F, 0xF0, 0x00, 0x08, + 0xCD, 0xE9, 0x62, 0x01, 0x54, 0x48, 0xC3, 0x46, 0xC1, 0x46, 0x47, 0x46, + 0x01, 0x21, 0x1C, 0x30, + 0x02, 0xF0, 0x0D, 0xFC, 0x50, 0x48, 0x01, 0x21, 0x24, 0x30, 0x02, 0xF0, + 0x08, 0xFC, 0x4E, 0x48, + 0x02, 0x21, 0x20, 0x30, 0x02, 0xF0, 0x03, 0xFC, 0x02, 0x21, 0x4F, 0x48, + 0x02, 0xF0, 0xA7, 0xFB, + 0x04, 0x21, 0x4E, 0x48, 0x02, 0xF0, 0xA3, 0xFB, 0x47, 0x4C, 0x4F, 0xF4, + 0x66, 0x75, 0x29, 0x46, + 0xE0, 0x69, 0x08, 0xF0, 0xA1, 0xFF, 0x29, 0x46, 0x60, 0x6A, 0x08, 0xF0, + 0x9D, 0xFF, 0x48, 0x48, + 0xB0, 0xF9, 0x00, 0x00, 0x41, 0x00, 0x20, 0x6A, 0x08, 0xF0, 0x96, 0xFF, + 0x29, 0x46, 0x45, 0x48, + 0x08, 0xF0, 0x92, 0xFF, 0x4F, 0xF0, 0x00, 0x0A, 0x55, 0x46, 0x84, 0xF8, + 0x01, 0xA0, 0xF8, 0xF7, + 0xFB, 0xFC, 0xF7, 0xF7, 0x41, 0xFE, 0x40, 0x48, 0x8D, 0xF8, 0x72, 0x51, + 0x01, 0x23, 0x00, 0x68, + 0x19, 0x90, 0x00, 0x22, 0x19, 0xA9, 0xA0, 0x69, 0x00, 0xF0, 0xE2, 0xFC, + 0x3B, 0x48, 0x5D, 0x95, + 0x00, 0x26, 0xB0, 0xF9, 0x00, 0x10, 0x2A, 0x48, 0xB0, 0xF9, 0x00, 0x00, + 0x04, 0xF0, 0x7C, 0xFF, + 0x00, 0xB2, 0x06, 0x90, 0x9D, 0xF8, 0x72, 0x01, 0x01, 0x28, 0x02, 0xD9, + 0x22, 0x49, 0x81, 0xF8, + 0x00, 0xA0, 0x0D, 0xF1, 0x56, 0x00, 0x01, 0x25, 0x60, 0x90, 0x9B, 0xE1, + 0x00, 0x20, 0x01, 0x90, + 0x19, 0xA8, 0x00, 0xEB, 0x85, 0x00, 0x05, 0x90, 0x19, 0xAA, 0x29, 0x46, + 0x07, 0xA8, 0x5D, 0x9B, + 0xFF, 0xF7, 0x96, 0xFC, 0x07, 0xAB, 0x29, 0x46, 0x05, 0x9A, 0x07, 0x98, + 0xFF, 0xF7, 0xB9, 0xFC, + 0x01, 0x24, 0x2B, 0x46, 0x5D, 0xAA, 0x07, 0xA9, 0x19, 0xA8, 0x00, 0x94, + 0xFF, 0xF7, 0x06, 0xFC, + 0x0D, 0xF1, 0x5A, 0x00, 0x00, 0xF0, 0xFE, 0xFA, 0x78, 0xB1, 0xBD, 0xF8, + 0x40, 0x00, 0x40, 0xF0, + 0x01, 0x00, 0xAD, 0xF8, 0x40, 0x00, 0x07, 0xA8, 0x00, 0xF0, 0x41, 0xFC, + 0x28, 0xB1, 0x1C, 0x48, + 0x14, 0x49, 0x00, 0x88, 0x08, 0x80, 0x0A, 0x49, 0x08, 0x80, 0x06, 0x48, + 0x00, 0x78, 0x88, 0xB3, + 0xBD, 0xF8, 0x40, 0x00, 0x10, 0xF0, 0x06, 0x0F, 0x30, 0xD1, 0x2C, 0xE0, + 0x74, 0x07, 0x10, 0x00, + 0xFD, 0x06, 0x10, 0x00, 0xA4, 0x06, 0x10, 0x00, 0x34, 0x06, 0x10, 0x00, + 0xA6, 0x06, 0x10, 0x00, + 0x92, 0x06, 0x10, 0x00, 0x04, 0x07, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x80, 0x06, 0x10, 0x00, + 0xF9, 0x06, 0x10, 0x00, 0x9A, 0x06, 0x10, 0x00, 0x38, 0x06, 0x10, 0x00, + 0xA8, 0x06, 0x10, 0x00, + 0x0A, 0x44, 0x01, 0x20, 0x94, 0x06, 0x10, 0x00, 0x60, 0x06, 0x10, 0x00, + 0x6C, 0x06, 0x10, 0x00, + 0xFE, 0x06, 0x10, 0x00, 0xC2, 0x18, 0x01, 0x20, 0x88, 0x06, 0x10, 0x00, + 0xAC, 0x06, 0x10, 0x00, + 0xA2, 0x06, 0x10, 0x00, 0x02, 0xE0, 0xFE, 0x48, 0x00, 0x68, 0x08, 0x90, + 0x05, 0x98, 0x00, 0xF0, + 0xC3, 0xFA, 0x28, 0xB1, 0xBD, 0xF8, 0x40, 0x00, 0x40, 0xF0, 0x08, 0x00, + 0xAD, 0xF8, 0x40, 0x00, + 0x01, 0x24, 0x5D, 0x98, 0xAC, 0x40, 0x04, 0x42, 0x41, 0xD1, 0xF6, 0x48, + 0x00, 0x78, 0xC0, 0x07, + 0x3D, 0xD0, 0xF5, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x28, 0x13, 0xF4, 0x48, + 0x00, 0x68, 0x81, 0x42, + 0xF3, 0x48, 0x40, 0x78, 0x01, 0xD2, 0x90, 0xBB, 0x01, 0xE0, 0x02, 0x28, + 0x2F, 0xD2, 0xF1, 0x48, + 0x5D, 0xAA, 0x07, 0xA9, 0xB0, 0xF9, 0x00, 0x00, 0x8D, 0xE8, 0x07, 0x00, + 0xEE, 0x48, 0x2A, 0x46, + 0x05, 0x9B, 0x81, 0x69, 0x40, 0x6A, 0xFF, 0xF7, 0xD9, 0xFC, 0x01, 0x90, + 0xB8, 0xB9, 0x07, 0xAB, + 0x29, 0x46, 0x05, 0x9A, 0x07, 0x98, 0x00, 0xF0, 0xA6, 0xF9, 0x80, 0xB1, + 0x4F, 0xF0, 0x02, 0x0C, + 0x8D, 0xF8, 0x5C, 0xC0, 0x29, 0x46, 0x07, 0xAB, 0x05, 0x9A, 0x07, 0x98, + 0xAD, 0xF8, 0x4A, 0xC0, + 0xAD, 0xF8, 0x4C, 0xC0, 0xFF, 0xF7, 0x9C, 0xFB, 0x4F, 0xF0, 0x01, 0x0B, + 0xCF, 0xE0, 0x2B, 0x46, + 0x5D, 0xAA, 0x07, 0xA9, 0x19, 0xA8, 0xCD, 0xF8, 0x00, 0xA0, 0xFF, 0xF7, + 0x67, 0xFB, 0xBD, 0xF9, + 0x4E, 0x00, 0x06, 0x99, 0x88, 0x42, 0x6A, 0xDD, 0x00, 0x95, 0x5D, 0xAA, + 0x07, 0xA9, 0x19, 0xA8, + 0x05, 0x9B, 0xFF, 0xF7, 0x13, 0xFE, 0x00, 0x28, 0x7E, 0xD1, 0x5D, 0x98, + 0x04, 0x42, 0x3A, 0xD1, + 0xBD, 0xF8, 0x40, 0x00, 0x10, 0xF4, 0xC0, 0x7F, 0x35, 0xD1, 0xD0, 0x48, + 0x5D, 0xAA, 0x07, 0xA9, + 0xB0, 0xF9, 0x00, 0x00, 0x8D, 0xE8, 0x07, 0x00, 0xCB, 0x48, 0x2A, 0x46, + 0x05, 0x9B, 0x81, 0x69, + 0x40, 0x6A, 0xFF, 0xF7, 0x93, 0xFC, 0x01, 0x90, 0x5D, 0x98, 0x04, 0x42, + 0x23, 0xD0, 0xC2, 0x48, + 0xBD, 0xF8, 0x42, 0x20, 0x00, 0x68, 0x90, 0xF8, 0x0E, 0x33, 0x9A, 0x42, + 0x05, 0xD8, 0x90, 0xF8, + 0xE0, 0x02, 0x82, 0x07, 0x17, 0xD4, 0x40, 0x07, 0x15, 0xD4, 0x01, 0x23, + 0x5D, 0xAA, 0x07, 0xA9, + 0x19, 0xA8, 0x8D, 0xE8, 0x0F, 0x00, 0xBC, 0x48, 0x2A, 0x46, 0x60, 0x9B, + 0x41, 0x6A, 0x80, 0x69, + 0xFF, 0xF7, 0x9A, 0xFC, 0x01, 0x90, 0x01, 0x20, 0x00, 0x90, 0x2B, 0x46, + 0x5D, 0xAA, 0x07, 0xA9, + 0x19, 0xA8, 0xFF, 0xF7, 0x1B, 0xFB, 0x01, 0x98, 0xC8, 0xB9, 0xBD, 0xF8, + 0x42, 0x00, 0x07, 0xA9, + 0xFF, 0xF7, 0xE3, 0xFC, 0x98, 0xB1, 0x07, 0xA8, 0x00, 0x90, 0xB1, 0x48, + 0x29, 0x46, 0x60, 0x9A, + 0xB0, 0xF9, 0x00, 0x30, 0xAC, 0x48, 0x80, 0x69, 0x00, 0xF0, 0x84, 0xF9, + 0x07, 0xAB, 0x29, 0x46, + 0x05, 0x9A, 0x07, 0x98, 0xFF, 0xF7, 0xE9, 0xFC, 0x4F, 0xF0, 0x01, 0x08, + 0x5F, 0xE0, 0x2B, 0x46, + 0x5D, 0xAA, 0x07, 0xA9, 0x19, 0xA8, 0xCD, 0xF8, 0x00, 0xA0, 0xFF, 0xF7, + 0xF7, 0xFA, 0xA4, 0x48, + 0xBD, 0xF9, 0x4E, 0x10, 0xB0, 0xF9, 0x00, 0x00, 0x81, 0x42, 0x50, 0xDD, + 0xFF, 0xF7, 0x71, 0xFD, + 0xF0, 0xB3, 0x5D, 0x98, 0x04, 0x42, 0x2F, 0xD1, 0x9D, 0x48, 0x5D, 0xAA, + 0x07, 0xA9, 0xB0, 0xF9, + 0x00, 0x00, 0x8D, 0xE8, 0x07, 0x00, 0x98, 0x48, 0x2A, 0x46, 0x05, 0x9B, + 0x81, 0x69, 0x40, 0x6A, + 0xFF, 0xF7, 0x2C, 0xFC, 0x01, 0x90, 0x00, 0xE0, 0x52, 0xE0, 0x8F, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0x40, 0x03, 0xC0, 0x06, 0x18, 0xD4, 0x5D, 0x98, 0x04, 0x42, 0x15, 0xD0, + 0x01, 0x23, 0x5D, 0xAA, + 0x07, 0xA9, 0x19, 0xA8, 0x8D, 0xE8, 0x0F, 0x00, 0x8B, 0x48, 0x2A, 0x46, + 0x60, 0x9B, 0x41, 0x6A, + 0x80, 0x69, 0xFF, 0xF7, 0x39, 0xFC, 0x01, 0x90, 0x01, 0x20, 0x00, 0x90, + 0x2B, 0x46, 0x5D, 0xAA, + 0x07, 0xA9, 0x19, 0xA8, 0xFF, 0xF7, 0xBA, 0xFA, 0x01, 0x98, 0x80, 0xB9, + 0xBD, 0xF8, 0x42, 0x00, + 0x07, 0xA9, 0xFF, 0xF7, 0x4A, 0xFD, 0x50, 0xB1, 0x07, 0xAB, 0x29, 0x46, + 0x05, 0x9A, 0x00, 0xE0, + 0x0D, 0xE0, 0x07, 0x98, 0x00, 0xF0, 0x6F, 0xF9, 0x4F, 0xF0, 0x01, 0x09, + 0x07, 0xE0, 0x2B, 0x46, + 0x5D, 0xAA, 0x07, 0xA9, 0x19, 0xA8, 0xCD, 0xF8, 0x00, 0xA0, 0xFF, 0xF7, + 0x9F, 0xFA, 0x5D, 0x99, + 0x44, 0xEA, 0x01, 0x00, 0x73, 0x49, 0x5D, 0x90, 0x63, 0x98, 0x08, 0x80, + 0x73, 0x49, 0x62, 0x98, + 0x08, 0x80, 0x74, 0x48, 0x01, 0x78, 0x31, 0xB1, 0x9D, 0xF8, 0x72, 0x11, + 0x26, 0x43, 0x01, 0x29, + 0x01, 0xD9, 0x80, 0xF8, 0x00, 0xA0, 0xBD, 0xF8, 0x40, 0x00, 0xC0, 0x05, + 0x00, 0xD5, 0x27, 0x43, + 0x6D, 0x1C, 0xED, 0xB2, 0x9D, 0xF8, 0x72, 0x01, 0xA8, 0x42, 0xBF, 0xF4, + 0x5F, 0xAE, 0x66, 0x48, + 0x6A, 0x4A, 0x69, 0x4B, 0x41, 0x78, 0xA2, 0xF5, 0x66, 0x70, 0x01, 0xF0, + 0x7A, 0xFC, 0x68, 0x48, + 0x9D, 0xF8, 0x72, 0x11, 0x00, 0xF8, 0x05, 0x1F, 0x68, 0x49, 0x06, 0x83, + 0x87, 0x83, 0x65, 0x48, + 0x80, 0xF8, 0x00, 0xB0, 0x64, 0x48, 0x80, 0xF8, 0x00, 0x80, 0x81, 0xF8, + 0x00, 0x90, 0x02, 0x21, + 0x63, 0x48, 0x02, 0xF0, 0xC1, 0xF9, 0x04, 0x21, 0x62, 0x48, 0x02, 0xF0, + 0xBD, 0xF9, 0x56, 0x48, + 0x01, 0x21, 0x18, 0x30, 0x02, 0xF0, 0x86, 0xFA, 0x53, 0x48, 0x01, 0x21, + 0x1C, 0x30, 0x02, 0xF0, + 0x81, 0xFA, 0x51, 0x48, 0x01, 0x21, 0x24, 0x30, 0x02, 0xF0, 0x7C, 0xFA, + 0x4E, 0x48, 0x02, 0x21, + 0x20, 0x30, 0x02, 0xF0, 0x77, 0xFA, 0x67, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x51, 0x49, 0x00, 0x20, + 0x08, 0x70, 0x51, 0x49, 0x08, 0x70, 0x51, 0x49, 0x08, 0x70, 0x4A, 0x49, + 0x08, 0x70, 0xA8, 0x21, + 0x49, 0x48, 0x08, 0xF0, 0xA3, 0xBD, 0x44, 0x49, 0x00, 0x20, 0x4D, 0x4A, + 0x08, 0x62, 0x88, 0x61, + 0xC8, 0x61, 0x10, 0x60, 0x4B, 0x4A, 0x10, 0x60, 0x46, 0x4A, 0x10, 0x70, + 0x46, 0x4A, 0x10, 0x70, + 0x46, 0x4A, 0x10, 0x70, 0x3F, 0x4A, 0x10, 0x70, 0x48, 0x70, 0x70, 0x47, + 0x3A, 0x49, 0x10, 0xB5, + 0x00, 0x20, 0x48, 0x70, 0x4F, 0xF4, 0x66, 0x71, 0x43, 0x48, 0x08, 0xF0, + 0x65, 0xFD, 0x3A, 0x48, + 0xA8, 0x21, 0xA8, 0x38, 0x08, 0xF0, 0x82, 0xFD, 0xBD, 0xE8, 0x10, 0x40, + 0xA8, 0x21, 0x36, 0x48, + 0x08, 0xF0, 0x7C, 0xBD, 0x2D, 0xE9, 0xF7, 0x4F, 0x2F, 0x48, 0x0D, 0x46, + 0x41, 0x78, 0x0F, 0x29, + 0x01, 0xD2, 0x49, 0x1C, 0x41, 0x70, 0x01, 0xF0, 0xFF, 0x09, 0x30, 0x49, + 0x82, 0xF8, 0x41, 0x90, + 0x01, 0xEB, 0x89, 0x00, 0x29, 0x68, 0x01, 0x60, 0xA9, 0x78, 0x33, 0x48, + 0x08, 0xF0, 0x56, 0xFE, + 0x82, 0x46, 0xA8, 0x78, 0x19, 0xE0, 0x00, 0x98, 0x2C, 0x78, 0x00, 0xEB, + 0xC8, 0x0B, 0x0D, 0xE0, + 0xDB, 0xE9, 0x00, 0x67, 0x22, 0x46, 0x01, 0x20, 0x00, 0x21, 0x08, 0xF0, + 0x7F, 0xFC, 0x06, 0x40, + 0x0F, 0x40, 0x3E, 0x43, 0x01, 0xD0, 0x0A, 0xF8, 0x04, 0x90, 0x64, 0x1C, + 0x68, 0x78, 0xA0, 0x42, + 0xEE, 0xDA, 0x0A, 0xF1, 0x28, 0x0A, 0x08, 0xF1, 0x01, 0x00, 0xE9, 0x78, + 0x80, 0x46, 0x41, 0x45, + 0xE1, 0xDA, 0xBD, 0xE8, 0xFE, 0x8F, 0x2D, 0xE9, 0xF0, 0x41, 0x0F, 0x4C, + 0x10, 0x4F, 0xB3, 0xF8, + 0x26, 0xC0, 0x24, 0x68, 0x7F, 0x78, 0x00, 0x26, 0x94, 0xF8, 0x29, 0x53, + 0x17, 0xB1, 0x94, 0xF8, + 0x2A, 0x73, 0x3D, 0x44, 0x93, 0xF8, 0x24, 0xE0, 0x94, 0xF8, 0x2B, 0x73, + 0x5F, 0xEA, 0xCE, 0x7E, + 0x01, 0xD0, 0x94, 0xF8, 0x2C, 0x73, 0xAC, 0x45, 0x39, 0xD9, 0xBC, 0x45, + 0x37, 0xD8, 0x25, 0xE0, + 0x14, 0x07, 0x10, 0x00, 0x04, 0x07, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x7C, 0x06, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, 0x94, 0x06, 0x10, 0x00, 0x38, 0x06, 0x10, 0x00, + 0x92, 0x06, 0x10, 0x00, + 0x96, 0x06, 0x10, 0x00, 0x34, 0x06, 0x10, 0x00, 0x98, 0x46, 0x10, 0x00, + 0x5A, 0x1C, 0x01, 0x20, + 0x0A, 0x44, 0x01, 0x20, 0xF6, 0x06, 0x10, 0x00, 0xF7, 0x06, 0x10, 0x00, + 0xF8, 0x06, 0x10, 0x00, + 0x60, 0x06, 0x10, 0x00, 0x6C, 0x06, 0x10, 0x00, 0xC2, 0x18, 0x01, 0x20, + 0x45, 0x4F, 0xB3, 0xF9, + 0x32, 0x50, 0xB7, 0xF9, 0x00, 0x70, 0xBD, 0x42, 0x09, 0xDD, 0xB4, 0xF8, + 0x26, 0x43, 0x9D, 0x69, + 0xA5, 0x42, 0x04, 0xDA, 0x00, 0xF0, 0xDB, 0xFC, 0x01, 0x28, 0x00, 0xD1, + 0x01, 0x26, 0x30, 0x46, + 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, 0xFF, 0x5F, 0x8B, 0x46, 0x14, 0x46, + 0x91, 0x78, 0x0E, 0x9D, + 0x08, 0xF0, 0xC6, 0xFD, 0x06, 0x46, 0xA1, 0x78, 0x68, 0x68, 0x08, 0xF0, + 0xC7, 0xFD, 0x07, 0x46, + 0x4F, 0xF0, 0x00, 0x09, 0xFF, 0xF7, 0xF5, 0xFB, 0x00, 0x28, 0x32, 0xD0, + 0x32, 0x49, 0xB5, 0xF9, + 0x32, 0x00, 0xB1, 0xF9, 0x00, 0x10, 0x88, 0x42, 0x2B, 0xDC, 0x30, 0x48, + 0xA1, 0x78, 0xE3, 0x78, + 0x90, 0xF8, 0x00, 0xA0, 0x19, 0xE0, 0x20, 0x78, 0x62, 0x78, 0x0F, 0xE0, + 0x16, 0xF8, 0x00, 0x80, + 0xD8, 0x45, 0x09, 0xD1, 0x37, 0xF9, 0x10, 0x80, 0xDD, 0xF8, 0x0C, 0xC0, + 0xE0, 0x45, 0x03, 0xDD, + 0x09, 0xF1, 0x01, 0x0C, 0x1F, 0xFA, 0x8C, 0xF9, 0x40, 0x1C, 0xC0, 0xB2, + 0x82, 0x42, 0xED, 0xD2, + 0x49, 0x1C, 0x07, 0xEB, 0x4A, 0x07, 0xC9, 0xB2, 0x28, 0x36, 0x8B, 0x42, + 0xE3, 0xD2, 0x29, 0x46, + 0x48, 0x46, 0xFF, 0xF7, 0xDA, 0xFB, 0x00, 0x28, 0x03, 0xD0, 0xA8, 0x8C, + 0x40, 0xF4, 0x00, 0x70, + 0xA8, 0x84, 0xBD, 0xE8, 0xFF, 0x9F, 0x2D, 0xE9, 0xF0, 0x41, 0x80, 0x46, + 0x01, 0x20, 0x83, 0xF8, + 0x40, 0x00, 0x1C, 0x46, 0x16, 0x46, 0x0F, 0x46, 0x40, 0x46, 0x00, 0xF0, + 0x0B, 0xFC, 0x14, 0x4D, + 0x28, 0x68, 0x90, 0xF8, 0x40, 0x03, 0x41, 0x07, 0x04, 0xD5, 0x21, 0x46, + 0x30, 0x46, 0x00, 0xF0, + 0xDF, 0xFD, 0x05, 0xE0, 0x00, 0x07, 0x03, 0xD5, 0x21, 0x46, 0x30, 0x46, + 0x00, 0xF0, 0xC7, 0xFD, + 0x28, 0x68, 0x23, 0x46, 0x32, 0x46, 0x90, 0xF8, 0x40, 0x03, 0x39, 0x46, + 0xC0, 0x06, 0x40, 0x46, + 0x03, 0xD5, 0xBD, 0xE8, 0xF0, 0x41, 0x01, 0xF0, 0x86, 0xBB, 0xBD, 0xE8, + 0xF0, 0x41, 0xFF, 0xF7, + 0x37, 0xB9, 0x00, 0x00, 0x94, 0x06, 0x10, 0x00, 0x8C, 0x06, 0x10, 0x00, + 0xEE, 0x06, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x01, 0x78, 0x59, 0xB1, 0x80, 0x4A, 0x12, 0x78, + 0x52, 0x1E, 0x91, 0x42, + 0x06, 0xD0, 0x40, 0x78, 0x20, 0xB1, 0x7E, 0x49, 0x09, 0x78, 0x49, 0x1E, + 0x88, 0x42, 0x01, 0xD1, + 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x01, 0x78, 0x29, 0xB1, + 0x77, 0x49, 0x42, 0x78, + 0x09, 0x78, 0x49, 0x1E, 0x8A, 0x42, 0x09, 0xD1, 0x81, 0x78, 0x29, 0xB1, + 0xC1, 0x78, 0x74, 0x48, + 0x00, 0x78, 0x40, 0x1E, 0x81, 0x42, 0x01, 0xD1, 0x01, 0x20, 0x70, 0x47, + 0x00, 0x20, 0x70, 0x47, + 0xF0, 0xB5, 0x70, 0x4D, 0x00, 0x22, 0x05, 0xEB, 0xC2, 0x06, 0x00, 0x23, + 0xC6, 0xE9, 0x00, 0x33, + 0x52, 0x1C, 0xD2, 0xB2, 0x17, 0x2A, 0xF6, 0xD3, 0x8A, 0x78, 0x2C, 0xE0, + 0x00, 0xEB, 0xC2, 0x03, + 0xD3, 0xE9, 0x00, 0x76, 0x57, 0xEA, 0x06, 0x03, 0x23, 0xD0, 0x74, 0x08, + 0x4F, 0xEA, 0x37, 0x03, + 0x17, 0xEB, 0x07, 0x0E, 0x46, 0xEB, 0x06, 0x0C, 0x44, 0xEA, 0x0C, 0x04, + 0x34, 0x43, 0x43, 0xEA, + 0x0E, 0x03, 0x05, 0xEB, 0xC2, 0x06, 0x3B, 0x43, 0xD6, 0xE9, 0x00, 0x7C, + 0x1F, 0x43, 0x4C, 0xEA, + 0x04, 0x0C, 0xC6, 0xE9, 0x00, 0x7C, 0xD6, 0xE9, 0x02, 0x7C, 0x1F, 0x43, + 0x4C, 0xEA, 0x04, 0x0C, + 0xC6, 0xE9, 0x02, 0x7C, 0xD6, 0xE9, 0x04, 0x7C, 0x1F, 0x43, 0x4C, 0xEA, + 0x04, 0x0C, 0xC6, 0xE9, + 0x04, 0x7C, 0x52, 0x1C, 0xD2, 0xB2, 0xCB, 0x78, 0x93, 0x42, 0xCF, 0xD2, + 0x00, 0x22, 0x50, 0x4B, + 0x0A, 0xE0, 0x00, 0xBF, 0x05, 0xEB, 0xC2, 0x04, 0x00, 0xEB, 0xC2, 0x07, + 0xD4, 0xE9, 0x02, 0x64, + 0xC7, 0xE9, 0x00, 0x64, 0x52, 0x1C, 0xD2, 0xB2, 0x1C, 0x78, 0xA2, 0x42, + 0xF2, 0xD3, 0x08, 0x78, + 0x08, 0xB1, 0x40, 0x1E, 0x08, 0x70, 0x45, 0x4A, 0x48, 0x78, 0x12, 0x78, + 0x52, 0x1E, 0x90, 0x42, + 0x01, 0xDA, 0x40, 0x1C, 0x48, 0x70, 0x88, 0x78, 0x08, 0xB1, 0x40, 0x1E, + 0x88, 0x70, 0x1A, 0x78, + 0xC8, 0x78, 0x52, 0x1E, 0x90, 0x42, 0x01, 0xDA, 0x40, 0x1C, 0xC8, 0x70, + 0xF0, 0xBD, 0x2D, 0xE9, + 0xFF, 0x5F, 0x94, 0x78, 0x16, 0x46, 0x04, 0xEB, 0x84, 0x02, 0x8B, 0x46, + 0x00, 0xEB, 0xC2, 0x00, + 0x00, 0x21, 0x00, 0xF1, 0x29, 0x08, 0x20, 0xE0, 0x00, 0x20, 0x81, 0x46, + 0x82, 0x46, 0x35, 0x78, + 0x77, 0x78, 0x0F, 0xE0, 0x18, 0xF8, 0x05, 0x20, 0x5A, 0x45, 0x09, 0xD1, + 0x2A, 0x46, 0x01, 0x20, + 0x00, 0x21, 0x08, 0xF0, 0xEB, 0xFA, 0x41, 0xEA, 0x0A, 0x0A, 0x40, 0xEA, + 0x09, 0x09, 0x01, 0x21, + 0x6D, 0x1C, 0xED, 0xB2, 0xAF, 0x42, 0xED, 0xD2, 0x03, 0x9B, 0x08, 0xF1, + 0x28, 0x08, 0x03, 0xEB, + 0xC4, 0x03, 0x64, 0x1C, 0xC3, 0xE9, 0x00, 0x9A, 0xE4, 0xB2, 0xF0, 0x78, + 0xA0, 0x42, 0xDB, 0xD2, + 0x04, 0xB0, 0x08, 0x46, 0xBD, 0xE8, 0xF0, 0x9F, 0x0A, 0x78, 0x43, 0x78, + 0x9A, 0x42, 0x0B, 0xD8, + 0x4A, 0x78, 0x03, 0x78, 0x9A, 0x42, 0x07, 0xD3, 0x8A, 0x78, 0xC3, 0x78, + 0x9A, 0x42, 0x03, 0xD8, + 0xC9, 0x78, 0x80, 0x78, 0x81, 0x42, 0x01, 0xD2, 0x00, 0x20, 0x70, 0x47, + 0x01, 0x20, 0x70, 0x47, + 0x70, 0xB5, 0x0C, 0x78, 0x8B, 0x78, 0x4D, 0x78, 0xC9, 0x78, 0x9A, 0xB1, + 0x0C, 0xB1, 0x64, 0x1E, + 0xE4, 0xB2, 0x12, 0x4A, 0x12, 0x78, 0x52, 0x1E, 0x95, 0x42, 0x01, 0xDA, + 0x6D, 0x1C, 0xED, 0xB2, + 0x0B, 0xB1, 0x5B, 0x1E, 0xDB, 0xB2, 0x0E, 0x4A, 0x12, 0x78, 0x52, 0x1E, + 0x91, 0x42, 0x01, 0xDA, + 0x49, 0x1C, 0xC9, 0xB2, 0x03, 0xEB, 0x83, 0x02, 0x00, 0xEB, 0xC2, 0x02, + 0x00, 0x26, 0x29, 0x32, + 0x09, 0xE0, 0x20, 0x46, 0x02, 0xE0, 0x16, 0x54, 0x40, 0x1C, 0xC0, 0xB2, + 0xA8, 0x42, 0xFA, 0xD9, + 0x5B, 0x1C, 0xDB, 0xB2, 0x28, 0x32, 0x8B, 0x42, 0xF3, 0xD9, 0x70, 0xBD, + 0xEE, 0x06, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, 0x40, 0x47, 0x10, 0x00, 0x2D, 0xE9, 0xF0, 0x47, + 0xDF, 0xF8, 0xA0, 0x90, + 0x80, 0x46, 0x0C, 0x78, 0x99, 0xF8, 0x00, 0x00, 0x0D, 0x46, 0x80, 0x1E, + 0x01, 0x2C, 0x05, 0xD9, + 0x69, 0x78, 0x81, 0x42, 0x02, 0xDA, 0x00, 0x20, 0xBD, 0xE8, 0xF0, 0x87, + 0x02, 0x2C, 0x01, 0xD2, + 0x02, 0x27, 0x01, 0xE0, 0x6F, 0x78, 0xC4, 0xB2, 0x4F, 0xF0, 0x00, 0x0A, + 0xA9, 0x78, 0xD8, 0xF8, + 0x08, 0x00, 0x08, 0xF0, 0x2B, 0xFC, 0x06, 0x46, 0xA9, 0x78, 0xD8, 0xF8, + 0x04, 0x00, 0x08, 0xF0, + 0x25, 0xFC, 0xAA, 0x78, 0x01, 0x46, 0xED, 0x78, 0x99, 0xF8, 0x00, 0x30, + 0x13, 0xE0, 0x20, 0x46, + 0x0A, 0xE0, 0x00, 0xBF, 0x36, 0xF9, 0x10, 0xC0, 0x31, 0xF9, 0x10, 0x80, + 0xC4, 0x45, 0x02, 0xD0, + 0x4F, 0xF0, 0x01, 0x0A, 0x02, 0xE0, 0x40, 0x1C, 0xB8, 0x42, 0xF3, 0xD9, + 0x06, 0xEB, 0x43, 0x06, + 0x01, 0xEB, 0x43, 0x01, 0x52, 0x1C, 0x95, 0x42, 0xE9, 0xD2, 0x50, 0x46, + 0xCC, 0xE7, 0x08, 0x49, + 0x09, 0x78, 0x49, 0x1E, 0xCA, 0xB2, 0x90, 0xF8, 0x3E, 0x10, 0x09, 0xB1, + 0x91, 0x42, 0x05, 0xD1, + 0x81, 0x8C, 0x41, 0xF0, 0x04, 0x01, 0x81, 0x84, 0x01, 0x20, 0x70, 0x47, + 0x00, 0x20, 0x70, 0x47, + 0xEE, 0x06, 0x10, 0x00, 0x30, 0xB5, 0xB0, 0xB1, 0x88, 0x42, 0x14, 0xD0, + 0x02, 0xD2, 0x0A, 0x46, + 0x01, 0x46, 0x10, 0x46, 0xDE, 0x4A, 0x53, 0x68, 0x03, 0xEB, 0x40, 0x03, + 0x1C, 0x78, 0x8C, 0x42, + 0x09, 0xD0, 0x5C, 0x78, 0x8C, 0x42, 0x06, 0xD0, 0x95, 0x68, 0x2A, 0x5C, + 0x02, 0x2A, 0x02, 0xD2, + 0x54, 0x1C, 0x2C, 0x54, 0x99, 0x54, 0x08, 0x46, 0x30, 0xBD, 0xF0, 0xB5, + 0x03, 0xEB, 0x82, 0x04, + 0xA5, 0x78, 0x05, 0xEB, 0x85, 0x06, 0x00, 0xEB, 0xC6, 0x06, 0xE0, 0x78, + 0x28, 0x36, 0xA8, 0x42, + 0x0F, 0xD3, 0x20, 0x78, 0x07, 0xE0, 0x37, 0x18, 0x97, 0xF8, 0x01, 0xC0, + 0x94, 0x45, 0x00, 0xD1, + 0x79, 0x70, 0x40, 0x1C, 0xC0, 0xB2, 0x67, 0x78, 0x87, 0x42, 0xF4, 0xD2, + 0x6D, 0x1C, 0xED, 0xB2, + 0xEB, 0xE7, 0x03, 0xEB, 0x81, 0x00, 0x25, 0x68, 0x05, 0x60, 0x03, 0xEB, + 0x42, 0x00, 0x03, 0xEB, + 0x41, 0x01, 0x30, 0xF8, 0xB4, 0x2F, 0xA1, 0xF8, 0xB4, 0x20, 0xC2, 0x49, + 0x09, 0x68, 0x21, 0x60, + 0x00, 0x21, 0x01, 0x80, 0x93, 0xF8, 0x0E, 0x01, 0x40, 0x1E, 0x83, 0xF8, + 0x0E, 0x01, 0xF0, 0xBD, + 0x2D, 0xE9, 0xFF, 0x4F, 0x88, 0x46, 0x08, 0x46, 0x09, 0x78, 0x8F, 0xB0, + 0xFF, 0x29, 0x13, 0xD0, + 0x8A, 0x46, 0xB9, 0x49, 0x42, 0x78, 0x09, 0x78, 0x8A, 0x42, 0x00, 0xD2, + 0x51, 0x1C, 0xCE, 0xB2, + 0xB6, 0x49, 0x90, 0xF8, 0x02, 0x90, 0xC0, 0x78, 0x09, 0x78, 0x88, 0x42, + 0x01, 0xD2, 0x40, 0x1C, + 0x00, 0xE0, 0x08, 0x46, 0xC7, 0xB2, 0x04, 0xE0, 0x4F, 0xF0, 0x00, 0x0A, + 0x56, 0x46, 0xD1, 0x46, + 0x57, 0x46, 0x11, 0x98, 0x4F, 0xF0, 0x00, 0x0B, 0x08, 0xB1, 0x98, 0xF8, + 0x0E, 0xB1, 0xA8, 0x4A, + 0x11, 0x68, 0x01, 0xF1, 0x5A, 0x00, 0xC2, 0xE9, 0x01, 0x10, 0x02, 0x46, + 0x5F, 0xF0, 0x2C, 0x00, + 0x00, 0x23, 0x01, 0xF8, 0x10, 0x00, 0x13, 0x54, 0x40, 0x1E, 0xC0, 0xB2, + 0xF8, 0xD2, 0x0B, 0xF1, + 0x01, 0x00, 0x0D, 0x90, 0xC0, 0xB2, 0x06, 0x90, 0x0F, 0x98, 0x09, 0xEB, + 0x89, 0x01, 0x00, 0xEB, + 0xC1, 0x05, 0x09, 0xF1, 0x01, 0x00, 0x09, 0x95, 0x39, 0xE0, 0x00, 0xBF, + 0x0A, 0xF1, 0x01, 0x00, + 0x0A, 0x95, 0xC4, 0xB2, 0x28, 0x35, 0x2E, 0xE0, 0x29, 0x19, 0x08, 0x68, + 0xE0, 0xB1, 0x28, 0x5D, + 0x38, 0xB3, 0x11, 0xF8, 0x01, 0x1C, 0x00, 0x20, 0x01, 0xB1, 0x08, 0x46, + 0x0A, 0x99, 0x09, 0x5D, + 0x09, 0xB1, 0xFF, 0xF7, 0x57, 0xFF, 0x12, 0x99, 0x61, 0xB1, 0x0A, 0x99, + 0x21, 0x44, 0x0E, 0x91, + 0x11, 0xF8, 0x01, 0x1C, 0x09, 0xB1, 0xFF, 0xF7, 0x4D, 0xFF, 0x0E, 0x99, + 0x49, 0x78, 0x09, 0xB1, + 0xFF, 0xF7, 0x48, 0xFF, 0x18, 0xB1, 0x0B, 0xE0, 0xE4, 0x1C, 0xE4, 0xB2, + 0x09, 0xE0, 0x06, 0x98, + 0x2D, 0x28, 0x03, 0xD2, 0x41, 0x1C, 0xC9, 0xB2, 0x06, 0x91, 0x01, 0xE0, + 0x40, 0x1E, 0xC0, 0xB2, + 0x28, 0x55, 0x64, 0x1C, 0xE4, 0xB2, 0xB4, 0x42, 0xCE, 0xD9, 0x07, 0x98, + 0x40, 0x1C, 0xC0, 0xB2, + 0x07, 0x90, 0xB8, 0x42, 0xC2, 0xD9, 0x06, 0x98, 0x00, 0xF0, 0x99, 0xF8, + 0x06, 0x90, 0x0D, 0x98, + 0x00, 0x22, 0xC0, 0xB2, 0x77, 0x4C, 0x09, 0xE0, 0x08, 0xEB, 0x80, 0x03, + 0x21, 0x68, 0x19, 0x60, + 0x08, 0xEB, 0x40, 0x01, 0x40, 0x1C, 0xA1, 0xF8, 0xB4, 0x20, 0xC0, 0xB2, + 0x06, 0x99, 0x88, 0x42, + 0xF2, 0xD3, 0x09, 0x98, 0x4D, 0x46, 0x28, 0x30, 0x00, 0x90, 0x39, 0xE0, + 0x54, 0x46, 0x30, 0xE0, + 0x20, 0x44, 0x01, 0x21, 0x09, 0x58, 0xE9, 0xB3, 0x41, 0x78, 0x41, 0xB3, + 0x68, 0x4A, 0x52, 0x68, + 0x12, 0xF8, 0x11, 0x10, 0x41, 0x70, 0x08, 0xEB, 0x41, 0x00, 0x08, 0xEB, + 0x81, 0x09, 0x30, 0xF8, + 0xB4, 0x2F, 0x52, 0x1C, 0x02, 0x80, 0x99, 0xF8, 0x00, 0x10, 0x20, 0x46, + 0x04, 0xF0, 0xEC, 0xF9, + 0x89, 0xF8, 0x00, 0x00, 0x99, 0xF8, 0x01, 0x10, 0x20, 0x46, 0x04, 0xF0, + 0xE9, 0xF9, 0x89, 0xF8, + 0x01, 0x00, 0x99, 0xF8, 0x02, 0x10, 0x28, 0x46, 0x04, 0xF0, 0xDE, 0xF9, + 0x89, 0xF8, 0x02, 0x00, + 0x99, 0xF8, 0x03, 0x10, 0x28, 0x46, 0x04, 0xF0, 0xDB, 0xF9, 0x89, 0xF8, + 0x03, 0x00, 0x64, 0x1C, + 0xE4, 0xB2, 0x00, 0x98, 0xB4, 0x42, 0xCB, 0xD3, 0x28, 0x30, 0x6D, 0x1C, + 0xED, 0xB2, 0x00, 0x90, + 0xBD, 0x42, 0xC3, 0xD3, 0x06, 0x98, 0x40, 0x1E, 0xC2, 0xB2, 0x88, 0xF8, + 0x0E, 0x21, 0x11, 0x98, + 0x00, 0x28, 0x00, 0xE0, 0x0B, 0xE0, 0x0D, 0xD0, 0xA2, 0xEB, 0x0B, 0x00, + 0x01, 0x28, 0x09, 0xD1, + 0x11, 0x99, 0x0F, 0x98, 0x13, 0xB0, 0x43, 0x46, 0xBD, 0xE8, 0xF0, 0x4F, + 0xDD, 0xE6, 0xE4, 0x1C, + 0xE4, 0xB2, 0xDC, 0xE7, 0x13, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xF0, 0xB5, + 0x02, 0xEB, 0x81, 0x03, + 0x00, 0x26, 0x9D, 0x78, 0x18, 0xE0, 0x00, 0xBF, 0x05, 0xEB, 0x85, 0x04, + 0x00, 0xEB, 0xC4, 0x07, + 0x1C, 0x78, 0x28, 0x37, 0x0A, 0xE0, 0x00, 0xBF, 0x07, 0xEB, 0x04, 0x0C, + 0x9C, 0xF8, 0x01, 0xE0, + 0x8E, 0x45, 0x01, 0xD1, 0x8C, 0xF8, 0x01, 0x60, 0x64, 0x1C, 0xE4, 0xB2, + 0x93, 0xF8, 0x01, 0xC0, + 0xA4, 0x45, 0xF1, 0xD2, 0x6D, 0x1C, 0xED, 0xB2, 0xDC, 0x78, 0xAC, 0x42, + 0xE4, 0xD2, 0x31, 0x48, + 0x00, 0x68, 0x18, 0x60, 0x02, 0xEB, 0x41, 0x00, 0xA0, 0xF8, 0xB4, 0x60, + 0xF0, 0xBD, 0x2D, 0xE9, + 0xF0, 0x5F, 0x07, 0x46, 0x00, 0x25, 0xDF, 0xF8, 0xA8, 0xB0, 0x2C, 0xE0, + 0xDB, 0xF8, 0x08, 0x10, + 0x4E, 0x5D, 0xDB, 0xF8, 0x04, 0x10, 0x01, 0xEB, 0x45, 0x0A, 0x1A, 0xE0, + 0x0A, 0xEB, 0x06, 0x00, + 0x80, 0x46, 0x10, 0xF8, 0x01, 0x1C, 0x10, 0xF8, 0x02, 0x9C, 0x08, 0x46, + 0x00, 0xF0, 0x35, 0xF8, + 0x04, 0x46, 0x48, 0x46, 0x00, 0xF0, 0x31, 0xF8, 0x84, 0x42, 0x02, 0xD2, + 0x01, 0x46, 0x20, 0x46, + 0x0C, 0x46, 0xDB, 0xF8, 0x04, 0x10, 0x76, 0x1E, 0xF6, 0xB2, 0x01, 0xF8, + 0x10, 0x40, 0x08, 0xF8, + 0x02, 0x4C, 0x01, 0x2E, 0xE2, 0xD8, 0x04, 0xD1, 0x28, 0x46, 0x00, 0xF0, + 0x1E, 0xF8, 0x8A, 0xF8, + 0x00, 0x00, 0x6D, 0x1C, 0xED, 0xB2, 0xBD, 0x42, 0xD0, 0xD3, 0x00, 0x21, + 0x08, 0x46, 0xDB, 0xF8, + 0x04, 0x40, 0x0D, 0xE0, 0x04, 0xEB, 0x40, 0x02, 0x13, 0x78, 0x83, 0x42, + 0x03, 0xD1, 0x11, 0x70, + 0x49, 0x1C, 0xC9, 0xB2, 0x02, 0xE0, 0x14, 0xF8, 0x13, 0x30, 0x13, 0x70, + 0x40, 0x1C, 0xC0, 0xB2, + 0xB8, 0x42, 0xEF, 0xD3, 0x08, 0x46, 0xBD, 0xE8, 0xF0, 0x9F, 0x05, 0x4A, + 0xD2, 0xE9, 0x01, 0x12, + 0x02, 0xE0, 0x00, 0xBF, 0x11, 0xF8, 0x10, 0x00, 0x13, 0x5C, 0x00, 0x2B, + 0xFA, 0xD1, 0x70, 0x47, + 0x60, 0x06, 0x10, 0x00, 0x36, 0x7A, 0x01, 0x00, 0xEE, 0x06, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, + 0xF0, 0xB5, 0xB2, 0xF9, 0x00, 0x40, 0x06, 0x68, 0xB4, 0x42, 0x02, 0xDD, + 0xB3, 0xF9, 0x00, 0x10, + 0x30, 0xE0, 0x02, 0xEB, 0x41, 0x04, 0x34, 0xF9, 0x02, 0x5C, 0xB5, 0x42, + 0x04, 0xDA, 0x03, 0xEB, + 0x41, 0x01, 0x31, 0xF9, 0x02, 0x1C, 0x25, 0xE0, 0x00, 0x25, 0x2C, 0x46, + 0x4F, 0x1E, 0x0C, 0xE0, + 0x32, 0xF9, 0x14, 0xC0, 0xB4, 0x45, 0x07, 0xDC, 0x02, 0xEB, 0x44, 0x0C, + 0xBC, 0xF9, 0x02, 0xC0, + 0xB4, 0x45, 0x01, 0xDB, 0x25, 0x46, 0x0C, 0x46, 0x64, 0x1C, 0xBC, 0x42, + 0xF0, 0xDB, 0x32, 0xF9, + 0x15, 0x40, 0x03, 0xEB, 0x45, 0x01, 0x33, 0xF9, 0x15, 0x30, 0xB1, 0xF9, + 0x02, 0x10, 0x02, 0xEB, + 0x45, 0x02, 0x36, 0x1B, 0xC9, 0x1A, 0xB2, 0xF9, 0x02, 0x20, 0x71, 0x43, + 0x12, 0x1B, 0x91, 0xFB, + 0xF2, 0xF1, 0x19, 0x44, 0x01, 0x60, 0xF0, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, + 0x07, 0x46, 0x2A, 0x48, + 0x00, 0x68, 0x00, 0xF2, 0x0F, 0x53, 0xE9, 0xB1, 0x01, 0x29, 0x22, 0xD0, + 0x02, 0x29, 0x2C, 0xD0, + 0x03, 0x29, 0x31, 0xD0, 0x04, 0x29, 0x36, 0xD0, 0x00, 0x21, 0x0C, 0x46, + 0x0E, 0xEB, 0x01, 0x00, + 0x20, 0x44, 0x64, 0x28, 0x3D, 0xDC, 0x01, 0x29, 0x03, 0xDD, 0x38, 0x1D, + 0x63, 0x46, 0xFF, 0xF7, + 0xA7, 0xFF, 0x01, 0x2C, 0x35, 0xDD, 0x38, 0x46, 0x33, 0x46, 0x2A, 0x46, + 0x21, 0x46, 0xBD, 0xE8, + 0xF0, 0x41, 0x9D, 0xE7, 0x90, 0xF8, 0x08, 0x15, 0x90, 0xF8, 0x09, 0x45, + 0x90, 0xF8, 0x0A, 0xE5, + 0x05, 0xE0, 0x90, 0xF8, 0x08, 0x15, 0x90, 0xF8, 0x09, 0x45, 0x90, 0xF8, + 0x0B, 0xE5, 0x9C, 0x46, + 0x03, 0xEB, 0x41, 0x06, 0x03, 0xEB, 0x4E, 0x02, 0x18, 0xE0, 0x90, 0xF8, + 0x08, 0x15, 0x90, 0xF8, + 0x09, 0x45, 0x90, 0xF8, 0x0C, 0xE5, 0xF2, 0xE7, 0x90, 0xF8, 0x08, 0x15, + 0x90, 0xF8, 0x09, 0x45, + 0x90, 0xF8, 0x0D, 0xE5, 0xEB, 0xE7, 0x90, 0xF8, 0x08, 0x15, 0x90, 0xF8, + 0x09, 0x45, 0x90, 0xF8, + 0x0E, 0x05, 0x9C, 0x46, 0x03, 0xEB, 0x41, 0x06, 0x03, 0xEB, 0x40, 0x02, + 0x02, 0xEB, 0x41, 0x05, + 0xBC, 0xE7, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x30, 0xB5, 0x42, 0x78, + 0x03, 0x78, 0xCD, 0x8C, 0xD2, 0x1A, 0xC3, 0x78, 0x80, 0x78, 0x52, 0x1C, + 0x1B, 0x1A, 0x5B, 0x1C, + 0x05, 0xFB, 0x02, 0xF0, 0xD4, 0x18, 0x5D, 0x43, 0x40, 0x00, 0x6A, 0x00, + 0xB0, 0xFB, 0xF4, 0xF0, + 0xB2, 0xFB, 0xF4, 0xF2, 0x90, 0x42, 0x02, 0xD9, 0xC8, 0x85, 0x0A, 0x86, + 0x30, 0xBD, 0xCA, 0x85, + 0x08, 0x86, 0x30, 0xBD, 0x2D, 0xE9, 0xFF, 0x4F, 0x00, 0x27, 0x83, 0xB0, + 0x15, 0x46, 0x01, 0x97, + 0x00, 0x97, 0x3E, 0x46, 0x3C, 0x46, 0xBB, 0x46, 0x91, 0x78, 0x08, 0xF0, + 0x61, 0xF9, 0x82, 0x46, + 0xAB, 0x78, 0x95, 0xF8, 0x03, 0x90, 0x28, 0xE0, 0x29, 0x78, 0x95, 0xF8, + 0x01, 0xC0, 0x8E, 0x46, + 0x1D, 0xE0, 0x00, 0xBF, 0x1A, 0xF8, 0x01, 0x20, 0x04, 0x98, 0x82, 0x42, + 0x15, 0xD1, 0xA1, 0xEB, + 0x0E, 0x02, 0x52, 0x1C, 0xDD, 0xF8, 0x00, 0x80, 0xA9, 0xEB, 0x03, 0x00, + 0x02, 0xFB, 0x02, 0x88, + 0x40, 0x1C, 0xCD, 0xF8, 0x00, 0x80, 0xDD, 0xF8, 0x04, 0x80, 0x16, 0x44, + 0x02, 0xFB, 0x00, 0x82, + 0x00, 0xFB, 0x00, 0xBB, 0x04, 0x44, 0x7F, 0x1C, 0x01, 0x92, 0x49, 0x1C, + 0xC9, 0xB2, 0x8C, 0x45, + 0xE0, 0xD2, 0x5B, 0x1C, 0x0A, 0xF1, 0x28, 0x0A, 0xDB, 0xB2, 0x99, 0x45, + 0xD4, 0xD2, 0x4F, 0xF4, + 0x7A, 0x70, 0x70, 0x43, 0x90, 0xFB, 0xF7, 0xF1, 0x4F, 0xF4, 0x7A, 0x70, + 0x60, 0x43, 0x90, 0xFB, + 0xF7, 0xF3, 0x4F, 0xF4, 0x7A, 0x72, 0x01, 0xFB, 0x04, 0xF0, 0x71, 0x43, + 0x90, 0xFB, 0xF2, 0xF7, + 0x91, 0xFB, 0xF2, 0xF6, 0x63, 0x43, 0x93, 0xFB, 0xF2, 0xF3, 0x01, 0x98, + 0x00, 0x99, 0xC0, 0x1B, + 0x89, 0x1B, 0xAB, 0xEB, 0x03, 0x02, 0x06, 0x9C, 0x8B, 0x1A, 0x00, 0xD5, + 0x5B, 0x42, 0x00, 0x28, + 0x00, 0xDA, 0x40, 0x42, 0x03, 0xEB, 0x40, 0x00, 0x11, 0x44, 0x0A, 0x18, + 0x08, 0x1A, 0x52, 0x10, + 0x40, 0x10, 0x4F, 0xF4, 0x7A, 0x71, 0x48, 0x43, 0x90, 0xFB, 0xF2, 0xF0, + 0xC0, 0xF5, 0x7A, 0x70, + 0xA0, 0x85, 0x06, 0x99, 0x07, 0xB0, 0x28, 0x46, 0xBD, 0xE8, 0xF0, 0x4F, + 0x6E, 0xE7, 0x01, 0x20, + 0x70, 0x47, 0x00, 0x00, 0x2D, 0xE9, 0xF0, 0x5F, 0x8A, 0x46, 0x0A, 0x9F, + 0x00, 0x25, 0x98, 0x46, + 0x14, 0x46, 0x83, 0x46, 0x2E, 0x46, 0x39, 0x46, 0x08, 0xF0, 0xF0, 0xF8, + 0x30, 0xF9, 0x18, 0x00, + 0xA0, 0x42, 0x2E, 0xDD, 0x78, 0x1E, 0x44, 0xB2, 0x7F, 0x1C, 0x27, 0xE0, + 0x00, 0x2C, 0x21, 0xDB, + 0xB0, 0x48, 0x00, 0x78, 0x84, 0x42, 0x1D, 0xDA, 0xE1, 0xB2, 0x58, 0x46, + 0x08, 0xF0, 0xDE, 0xF8, + 0xAD, 0x49, 0x81, 0x46, 0xA8, 0xF1, 0x01, 0x00, 0x0A, 0x78, 0x40, 0xB2, + 0x08, 0xF1, 0x01, 0x01, + 0x0D, 0xE0, 0x00, 0x28, 0x07, 0xDB, 0x90, 0x42, 0x05, 0xDA, 0x39, 0xF9, + 0x10, 0xC0, 0x3A, 0xF9, + 0x15, 0x30, 0x0C, 0xFB, 0x03, 0x66, 0x6D, 0x1C, 0x40, 0x1C, 0xED, 0xB2, + 0x40, 0xB2, 0x88, 0x42, + 0xEF, 0xDD, 0x01, 0xE0, 0xED, 0x1C, 0xED, 0xB2, 0x64, 0x1C, 0x64, 0xB2, + 0xBC, 0x42, 0xD5, 0xDD, + 0x00, 0xE0, 0x06, 0x46, 0x01, 0x20, 0x96, 0xFB, 0xF0, 0xF0, 0x00, 0xB2, + 0xBD, 0xE8, 0xF0, 0x9F, + 0x2D, 0xE9, 0xFF, 0x4F, 0x83, 0xB0, 0x91, 0x46, 0x10, 0x99, 0x08, 0x78, + 0x00, 0xB1, 0x40, 0x1E, + 0xC4, 0xB2, 0x88, 0x78, 0x00, 0xB1, 0x40, 0x1E, 0xDF, 0xF8, 0x4C, 0xA2, + 0xC5, 0xB2, 0x4A, 0x78, + 0x9A, 0xF8, 0x00, 0x00, 0x43, 0x1E, 0x9A, 0x42, 0x01, 0xDA, 0x50, 0x1C, + 0x00, 0xE0, 0x40, 0x1E, + 0xDF, 0xF8, 0x30, 0xB2, 0xC6, 0xB2, 0xC9, 0x78, 0x9B, 0xF8, 0x00, 0x00, + 0x42, 0x1E, 0x91, 0x42, + 0x01, 0xDA, 0x48, 0x1C, 0x00, 0xE0, 0x40, 0x1E, 0xC7, 0xB2, 0xCC, 0xB9, + 0xA8, 0x46, 0x12, 0xE0, + 0x01, 0x46, 0x03, 0x98, 0x08, 0xF0, 0x98, 0xF8, 0xCD, 0xE9, 0x00, 0x80, + 0x23, 0x46, 0x49, 0x46, + 0x06, 0x9A, 0x04, 0x98, 0xFF, 0xF7, 0x86, 0xFF, 0x01, 0x99, 0x21, 0xF8, + 0x14, 0x00, 0x08, 0xF1, + 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x08, 0x40, 0x46, 0xB8, 0x45, 0xE9, 0xD9, + 0x64, 0x1C, 0xE4, 0xB2, + 0x79, 0x48, 0x00, 0x78, 0x40, 0x1E, 0x86, 0x42, 0x19, 0xD1, 0xA8, 0x46, + 0x12, 0xE0, 0x01, 0x46, + 0x03, 0x98, 0x08, 0xF0, 0x79, 0xF8, 0x82, 0x46, 0x33, 0x46, 0xCD, 0xF8, + 0x00, 0x80, 0x49, 0x46, + 0x06, 0x9A, 0x04, 0x98, 0xFF, 0xF7, 0x66, 0xFF, 0x2A, 0xF8, 0x16, 0x00, + 0x08, 0xF1, 0x01, 0x00, + 0x00, 0xF0, 0xFF, 0x08, 0x40, 0x46, 0xB8, 0x45, 0xE9, 0xD9, 0x76, 0x1E, + 0xF6, 0xB2, 0xC5, 0xB9, + 0x29, 0x46, 0x03, 0x98, 0x08, 0xF0, 0x60, 0xF8, 0x82, 0x46, 0xA0, 0x46, + 0x0C, 0xE0, 0x03, 0x46, + 0x00, 0x95, 0x49, 0x46, 0x06, 0x9A, 0x04, 0x98, 0xFF, 0xF7, 0x4C, 0xFF, + 0x2A, 0xF8, 0x18, 0x00, + 0x08, 0xF1, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x08, 0x40, 0x46, 0xB0, 0x45, + 0xEF, 0xD9, 0x6D, 0x1C, + 0xED, 0xB2, 0x9B, 0xF8, 0x00, 0x00, 0x40, 0x1E, 0x87, 0x42, 0x18, 0xD1, + 0x39, 0x46, 0x03, 0x98, + 0x08, 0xF0, 0x42, 0xF8, 0x82, 0x46, 0xA0, 0x46, 0x0C, 0xE0, 0x03, 0x46, + 0x00, 0x97, 0x49, 0x46, + 0x06, 0x9A, 0x04, 0x98, 0xFF, 0xF7, 0x2E, 0xFF, 0x2A, 0xF8, 0x18, 0x00, + 0x08, 0xF1, 0x01, 0x00, + 0x00, 0xF0, 0xFF, 0x08, 0x40, 0x46, 0xB0, 0x45, 0xEF, 0xD9, 0x7F, 0x1E, + 0xFF, 0xB2, 0xB9, 0xF9, + 0x12, 0x00, 0x5F, 0xEA, 0x00, 0x0A, 0x64, 0xD1, 0x4F, 0xF0, 0x01, 0x0A, + 0x61, 0xE0, 0x29, 0x46, + 0x03, 0x98, 0x08, 0xF0, 0x21, 0xF8, 0x01, 0x90, 0x68, 0x1E, 0xC1, 0xB2, + 0x04, 0x98, 0x08, 0xF0, + 0x0D, 0xF8, 0x00, 0x90, 0x29, 0x46, 0x04, 0x98, 0x08, 0xF0, 0x08, 0xF8, + 0x21, 0x46, 0x4C, 0xE0, + 0x30, 0xF9, 0x11, 0x20, 0x06, 0x9B, 0x9A, 0x42, 0x42, 0xDD, 0x00, 0x9A, + 0xB9, 0xF9, 0x00, 0x80, + 0x02, 0xEB, 0x41, 0x02, 0x00, 0x23, 0x32, 0xF9, 0x02, 0xCD, 0x0C, 0xFB, + 0x08, 0x33, 0xB2, 0xF9, + 0x02, 0xC0, 0xB9, 0xF9, 0x02, 0x80, 0x0C, 0xFB, 0x08, 0x33, 0xB2, 0xF9, + 0x04, 0xC0, 0xB9, 0xF9, + 0x04, 0x80, 0x0C, 0xFB, 0x08, 0x3B, 0x34, 0x4B, 0xB9, 0xF9, 0x06, 0x80, + 0x93, 0xF8, 0x00, 0xE0, + 0x02, 0xEB, 0x4E, 0x02, 0xB2, 0xF9, 0x00, 0xC0, 0x0C, 0xFB, 0x08, 0xB3, + 0xB2, 0xF9, 0x02, 0xC0, + 0xB9, 0xF9, 0x08, 0x80, 0x0C, 0xFB, 0x08, 0x33, 0xB2, 0xF9, 0x04, 0xC0, + 0xB9, 0xF9, 0x0A, 0x80, + 0x02, 0xEB, 0x4E, 0x02, 0x0C, 0xFB, 0x08, 0x3B, 0xB2, 0xF9, 0x00, 0xC0, + 0xB9, 0xF9, 0x0C, 0x80, + 0x0C, 0xFB, 0x08, 0xB3, 0xB2, 0xF9, 0x02, 0xC0, 0xB9, 0xF9, 0x0E, 0x80, + 0x0C, 0xFB, 0x08, 0x33, + 0xB2, 0xF9, 0x04, 0xC0, 0xB9, 0xF9, 0x10, 0x20, 0x0C, 0xFB, 0x02, 0x32, + 0x92, 0xFB, 0xFA, 0xF2, + 0x01, 0x9B, 0x23, 0xF8, 0x11, 0x20, 0x49, 0x1C, 0xC9, 0xB2, 0xB1, 0x42, + 0xB0, 0xD9, 0x6D, 0x1C, + 0xED, 0xB2, 0xBD, 0x42, 0x9B, 0xD9, 0x07, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, + 0x1C, 0xB5, 0x17, 0x4C, + 0x24, 0x68, 0x01, 0x94, 0x01, 0xAC, 0x00, 0x94, 0xFF, 0xF7, 0xF2, 0xFE, + 0x1C, 0xBD, 0x38, 0xB5, + 0x16, 0x4D, 0x00, 0x90, 0x12, 0x48, 0x0C, 0x46, 0x12, 0x4A, 0x00, 0x68, + 0xB0, 0xF9, 0xE2, 0x32, + 0x11, 0x48, 0x01, 0x68, 0x28, 0x68, 0xFF, 0xF7, 0xE3, 0xFE, 0x28, 0x68, + 0xA0, 0x60, 0x38, 0xBD, + 0x38, 0xB5, 0x0E, 0x4D, 0x00, 0x90, 0x0A, 0x48, 0x0C, 0x46, 0x0A, 0x4A, + 0x00, 0x68, 0x14, 0x3A, + 0xB0, 0xF9, 0xE2, 0x32, 0x08, 0x48, 0x01, 0x68, 0x28, 0x68, 0xFF, 0xF7, + 0xD1, 0xFE, 0x28, 0x68, + 0x60, 0x60, 0x38, 0xBD, 0xED, 0x06, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, + 0x88, 0x06, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x22, 0x7A, 0x01, 0x00, 0x10, 0x07, 0x10, 0x00, + 0x58, 0x06, 0x10, 0x00, + 0x2D, 0xE9, 0xFF, 0x5F, 0x89, 0x46, 0x14, 0x46, 0x91, 0x78, 0x0F, 0x9D, + 0x07, 0xF0, 0x68, 0xFF, + 0x82, 0x46, 0xA1, 0x78, 0xA8, 0x68, 0x07, 0xF0, 0x69, 0xFF, 0x47, 0xF6, + 0xFF, 0x76, 0xA7, 0x78, + 0xF5, 0x43, 0xFE, 0x49, 0x94, 0xF8, 0x03, 0x80, 0x91, 0xF8, 0x00, 0xB0, + 0x18, 0xE0, 0x22, 0x78, + 0x94, 0xF8, 0x01, 0xC0, 0x0D, 0xE0, 0x00, 0xBF, 0x1A, 0xF8, 0x02, 0x10, + 0x49, 0x45, 0x07, 0xD1, + 0x30, 0xF9, 0x12, 0x30, 0xB3, 0x42, 0x00, 0xDA, 0x1E, 0x46, 0xAB, 0x42, + 0x00, 0xDD, 0x1D, 0x46, + 0x52, 0x1C, 0x94, 0x45, 0xF0, 0xD2, 0x0A, 0xF1, 0x28, 0x0A, 0x00, 0xEB, + 0x4B, 0x00, 0x7F, 0x1C, + 0xB8, 0x45, 0xE4, 0xD2, 0x03, 0x98, 0x06, 0x80, 0x0E, 0x98, 0x05, 0x80, + 0xBD, 0xE8, 0xFF, 0x9F, + 0x2D, 0xE9, 0xFF, 0x4F, 0xEA, 0x48, 0x85, 0xB0, 0x9A, 0x46, 0x04, 0x68, + 0x03, 0xA9, 0xCD, 0xE9, + 0x00, 0x1A, 0xDD, 0xE9, 0x05, 0x01, 0x15, 0x46, 0x04, 0xF5, 0x88, 0x79, + 0x02, 0xAB, 0xFF, 0xF7, + 0xB7, 0xFF, 0xE4, 0x48, 0xBD, 0xF9, 0x0C, 0x20, 0xDF, 0xF8, 0x8C, 0xB3, + 0x00, 0x68, 0x5F, 0x46, + 0x90, 0xF8, 0xE4, 0x12, 0xBD, 0xF9, 0x08, 0x00, 0x12, 0x1A, 0x4A, 0x43, + 0x64, 0x21, 0x92, 0xFB, + 0xF1, 0xF1, 0x0E, 0x18, 0x01, 0x22, 0x29, 0x46, 0xDB, 0xF8, 0x00, 0x00, + 0xFF, 0xF7, 0x98, 0xFA, + 0xD7, 0xF8, 0x00, 0x80, 0xDD, 0xE9, 0x05, 0x07, 0x31, 0xB2, 0x01, 0x91, + 0xA9, 0x78, 0x07, 0xF0, + 0x07, 0xFF, 0x06, 0x46, 0xA9, 0x78, 0x40, 0x46, 0x07, 0xF0, 0x10, 0xFF, + 0x00, 0x90, 0xA9, 0x78, + 0xDA, 0xF8, 0x08, 0x00, 0x07, 0xF0, 0x02, 0xFF, 0x01, 0x46, 0xAA, 0x78, + 0x01, 0x23, 0xDF, 0xF8, + 0x2C, 0xE3, 0x1D, 0xE0, 0x28, 0x78, 0x0E, 0xE0, 0x16, 0xF8, 0x00, 0xC0, + 0xBC, 0x45, 0x09, 0xD1, + 0x31, 0xF9, 0x10, 0x80, 0xDD, 0xF8, 0x04, 0xC0, 0xE0, 0x45, 0x03, 0xDD, + 0xDD, 0xF8, 0x00, 0xC0, + 0x0C, 0xF8, 0x00, 0x30, 0x40, 0x1C, 0x95, 0xF8, 0x01, 0xC0, 0x84, 0x45, + 0xEC, 0xD2, 0x00, 0x98, + 0x52, 0x1C, 0x28, 0x30, 0x00, 0x90, 0x9E, 0xF8, 0x00, 0x00, 0x28, 0x36, + 0x01, 0xEB, 0x40, 0x01, + 0xE8, 0x78, 0x90, 0x42, 0xDE, 0xD2, 0x00, 0x20, 0x84, 0xF8, 0x0E, 0x01, + 0x28, 0x68, 0x20, 0x60, + 0x01, 0x23, 0x00, 0x22, 0x21, 0x46, 0x5E, 0x46, 0xDB, 0xF8, 0x00, 0x00, + 0xFF, 0xF7, 0x28, 0xFB, + 0x94, 0xF8, 0x0E, 0x01, 0x01, 0x28, 0x26, 0xD9, 0x01, 0x25, 0x1D, 0xE0, + 0x48, 0x22, 0x51, 0x46, + 0x48, 0x46, 0x07, 0xF0, 0x7F, 0xFD, 0x04, 0xEB, 0x45, 0x00, 0x04, 0xEB, + 0x85, 0x07, 0xB0, 0xF8, + 0xB4, 0x10, 0xA9, 0xF8, 0x26, 0x10, 0x49, 0x46, 0x38, 0x46, 0xFF, 0xF7, + 0x27, 0xFD, 0x3A, 0x46, + 0xE9, 0xB2, 0x4B, 0x46, 0x30, 0x68, 0xFE, 0xF7, 0x0C, 0xFB, 0x3A, 0x46, + 0xE9, 0xB2, 0x4B, 0x46, + 0x30, 0x68, 0xFE, 0xF7, 0x85, 0xFA, 0x6D, 0x1C, 0x94, 0xF8, 0x0E, 0x01, + 0xA8, 0x42, 0xDD, 0xD2, + 0x09, 0xB0, 0xBD, 0xE8, 0xF0, 0x8F, 0xDD, 0xE9, 0x05, 0x01, 0x53, 0x46, + 0x2A, 0x46, 0xFE, 0xF7, + 0x77, 0xFA, 0xF5, 0xE7, 0x2D, 0xE9, 0xFF, 0x5F, 0x06, 0x46, 0x9A, 0x48, + 0x1D, 0x46, 0x0B, 0x46, + 0x00, 0x68, 0xDD, 0xE9, 0x0F, 0xB4, 0x92, 0x46, 0x98, 0x49, 0xB0, 0xF9, + 0xE6, 0x22, 0x00, 0x92, + 0x09, 0x78, 0x11, 0xB1, 0xB0, 0xF9, 0x62, 0x03, 0x00, 0x90, 0x18, 0x46, + 0x0E, 0x99, 0x07, 0xF0, + 0x7F, 0xFE, 0x81, 0x46, 0x30, 0x46, 0x0E, 0x99, 0x07, 0xF0, 0x88, 0xFE, + 0x03, 0x90, 0xA0, 0x68, + 0x0E, 0x99, 0x07, 0xF0, 0x7B, 0xFE, 0x2C, 0x78, 0x6D, 0x78, 0x80, 0x46, + 0x5C, 0xB9, 0x99, 0xF8, + 0x00, 0x10, 0x51, 0x45, 0x06, 0xD1, 0xB8, 0xF9, 0x00, 0x10, 0x59, 0x45, + 0x02, 0xDD, 0x03, 0x99, + 0x01, 0x20, 0x08, 0x70, 0x01, 0x24, 0x81, 0x48, 0x00, 0x78, 0x40, 0x1E, + 0x85, 0x42, 0x54, 0xD1, + 0x19, 0xF8, 0x05, 0x10, 0x51, 0x45, 0x06, 0xD1, 0x38, 0xF9, 0x15, 0x10, + 0x59, 0x45, 0x02, 0xDD, + 0x03, 0x99, 0x01, 0x20, 0x48, 0x55, 0x6D, 0x1E, 0xED, 0xB2, 0x46, 0xE0, + 0x19, 0xF8, 0x04, 0x10, + 0x51, 0x45, 0x41, 0xD1, 0x38, 0xF9, 0x14, 0x00, 0x01, 0x90, 0x58, 0x45, + 0x3C, 0xDD, 0x00, 0x20, + 0x02, 0x90, 0x77, 0x49, 0x0E, 0x98, 0x22, 0x46, 0x01, 0xEB, 0xC0, 0x00, + 0x00, 0x21, 0xD0, 0xE9, + 0x00, 0x67, 0x01, 0x20, 0x07, 0xF0, 0x82, 0xFC, 0x06, 0x40, 0x0F, 0x40, + 0x3E, 0x43, 0x28, 0xD1, + 0xDD, 0xE9, 0x00, 0x01, 0x08, 0xEB, 0x44, 0x02, 0x08, 0x44, 0x32, 0xF9, + 0x02, 0x1C, 0x00, 0xB2, + 0x81, 0x42, 0x05, 0xDD, 0xB2, 0xF9, 0x02, 0x30, 0x83, 0x42, 0x01, 0xDD, + 0x01, 0x23, 0x02, 0x93, + 0x01, 0x2C, 0x09, 0xD9, 0x32, 0xF9, 0x04, 0x3C, 0x83, 0x42, 0x05, 0xDD, + 0xB2, 0xF9, 0x02, 0x30, + 0x83, 0x42, 0x01, 0xDD, 0x01, 0x23, 0x02, 0x93, 0x5C, 0x4B, 0x1B, 0x78, + 0x9B, 0x1E, 0x9C, 0x42, + 0x05, 0xD2, 0x81, 0x42, 0x03, 0xDD, 0xB2, 0xF9, 0x04, 0x10, 0x81, 0x42, + 0x04, 0xDC, 0x02, 0x98, + 0x10, 0xB9, 0x03, 0x99, 0x01, 0x20, 0x08, 0x55, 0x64, 0x1C, 0xAC, 0x42, + 0xB6, 0xD9, 0xCD, 0xE6, + 0x2D, 0xE9, 0xFF, 0x4F, 0xDF, 0xF8, 0x54, 0xA1, 0xDF, 0xF8, 0x48, 0x81, + 0x9B, 0xB0, 0x8B, 0x46, + 0x9A, 0xF8, 0x00, 0x10, 0x28, 0x9E, 0xD8, 0xF8, 0x00, 0x00, 0x1D, 0x46, + 0x11, 0xB1, 0x90, 0xF8, + 0x68, 0x43, 0x01, 0xE0, 0x90, 0xF8, 0xE5, 0x42, 0x4E, 0x4F, 0xAC, 0xB1, + 0x03, 0xA8, 0xCD, 0xE9, + 0x00, 0x06, 0x02, 0xAB, 0x2A, 0x46, 0x58, 0x46, 0x1D, 0x99, 0xFF, 0xF7, + 0x79, 0xFE, 0xBD, 0xF9, + 0x0C, 0x00, 0xBD, 0xF9, 0x08, 0x10, 0x40, 0x1A, 0x60, 0x43, 0x64, 0x21, + 0x90, 0xFB, 0xF1, 0xF0, + 0x39, 0x88, 0x08, 0x44, 0x00, 0xB2, 0x01, 0xE0, 0xB7, 0xF9, 0x00, 0x00, + 0x42, 0x49, 0x81, 0x46, + 0x38, 0x88, 0x08, 0x80, 0x41, 0x49, 0xA1, 0xF8, 0x00, 0x90, 0xD8, 0xF8, + 0x00, 0x00, 0xB0, 0xF9, + 0xE6, 0x12, 0x11, 0x91, 0xB0, 0xF9, 0xE8, 0x12, 0x0C, 0x91, 0x9A, 0xF8, + 0x00, 0x10, 0x29, 0xB1, + 0xB0, 0xF9, 0x62, 0x13, 0x11, 0x91, 0xB0, 0xF9, 0x64, 0x03, 0x0C, 0x90, + 0xAC, 0x78, 0x95, 0xF8, + 0x03, 0x80, 0x4C, 0xB9, 0xCD, 0xE9, 0x00, 0x49, 0x02, 0x96, 0x2B, 0x46, + 0x59, 0x46, 0x1D, 0x9A, + 0x1B, 0x98, 0xFF, 0xF7, 0x1F, 0xFF, 0x01, 0x24, 0x31, 0x49, 0x09, 0x78, + 0x49, 0x1E, 0x88, 0x45, + 0x0D, 0xD1, 0xCD, 0xF8, 0x00, 0x80, 0xCD, 0xE9, 0x01, 0x96, 0x2B, 0x46, + 0x59, 0x46, 0x1D, 0x9A, + 0x1B, 0x98, 0xFF, 0xF7, 0x0F, 0xFF, 0xA8, 0xF1, 0x01, 0x00, 0x00, 0xF0, + 0xFF, 0x08, 0xA0, 0x1E, + 0xC1, 0xB2, 0xB0, 0x68, 0x07, 0xF0, 0xA2, 0xFD, 0x0D, 0x90, 0x60, 0x1E, + 0xC1, 0xB2, 0xB0, 0x68, + 0x07, 0xF0, 0x9C, 0xFD, 0x03, 0x90, 0x21, 0x46, 0xB0, 0x68, 0x07, 0xF0, + 0x97, 0xFD, 0x02, 0x90, + 0x60, 0x1C, 0xC1, 0xB2, 0xB0, 0x68, 0x07, 0xF0, 0x91, 0xFD, 0x01, 0x90, + 0xA0, 0x1C, 0xC1, 0xB2, + 0xB0, 0x68, 0x07, 0xF0, 0x8B, 0xFD, 0x04, 0x90, 0x21, 0x46, 0x58, 0x46, + 0x07, 0xF0, 0x80, 0xFD, + 0x83, 0x46, 0x21, 0x46, 0x1B, 0x98, 0x07, 0xF0, 0x89, 0xFD, 0x05, 0x90, + 0x00, 0x20, 0x14, 0x90, + 0x01, 0x20, 0x13, 0x90, 0x00, 0x20, 0x12, 0x90, 0x0A, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x40, 0x14, + 0xCA, 0x07, 0x29, 0xD0, 0x09, 0x07, 0x27, 0xD5, 0x69, 0x78, 0x2A, 0x78, + 0x8A, 0x1A, 0x90, 0xF8, + 0x49, 0x14, 0x52, 0x1C, 0x8A, 0x42, 0x1F, 0xDC, 0xEA, 0x78, 0x13, 0xE0, + 0xEE, 0x06, 0x10, 0x00, + 0x6C, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x54, 0x06, 0x10, 0x00, + 0xFD, 0x06, 0x10, 0x00, + 0x98, 0x46, 0x10, 0x00, 0x92, 0x06, 0x10, 0x00, 0x8E, 0x07, 0x10, 0x00, + 0x90, 0x07, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, 0xAB, 0x78, 0xD2, 0x1A, 0x52, 0x1C, 0x8A, 0x42, + 0x04, 0xDC, 0xB0, 0xF8, + 0x47, 0x04, 0xB1, 0x69, 0x81, 0x42, 0x01, 0xDD, 0x00, 0x20, 0x13, 0x90, + 0xA2, 0x46, 0xF1, 0xE0, + 0x2C, 0x78, 0xCE, 0xE0, 0x1B, 0xF8, 0x04, 0x10, 0x1D, 0x98, 0x81, 0x42, + 0x6B, 0xD1, 0x00, 0x20, + 0x10, 0x90, 0xFB, 0x49, 0x16, 0x90, 0x15, 0x90, 0x01, 0xEB, 0xCA, 0x00, + 0x22, 0x46, 0xD0, 0xE9, + 0x00, 0x67, 0x01, 0x20, 0x00, 0x21, 0x07, 0xF0, 0x71, 0xFB, 0x06, 0x40, + 0x0F, 0x40, 0x3E, 0x43, + 0x7E, 0xD1, 0xF4, 0x49, 0x40, 0xF2, 0xD2, 0x40, 0x08, 0x80, 0x02, 0x98, + 0x0C, 0x9A, 0x30, 0xF8, + 0x14, 0x10, 0x11, 0x98, 0x08, 0x44, 0x11, 0x44, 0x03, 0x9A, 0x00, 0xB2, + 0x09, 0xB2, 0x32, 0xF9, + 0x14, 0x20, 0x82, 0x42, 0x07, 0xDD, 0x01, 0x9B, 0x33, 0xF9, 0x14, 0x30, + 0x83, 0x42, 0x02, 0xDD, + 0x01, 0x23, 0x10, 0x93, 0x15, 0x93, 0xEC, 0xB3, 0xE7, 0x4B, 0x93, 0xF8, + 0x00, 0xE0, 0xAE, 0xF1, + 0x01, 0x03, 0x9C, 0x42, 0x68, 0xD0, 0x02, 0x9B, 0x03, 0xEB, 0x44, 0x0C, + 0x3C, 0xF9, 0x02, 0x6C, + 0x86, 0x42, 0x06, 0xDD, 0xBC, 0xF9, 0x02, 0x30, 0x83, 0x42, 0x02, 0xDD, + 0x01, 0x23, 0x10, 0x93, + 0x16, 0x93, 0x03, 0x9B, 0x03, 0xEB, 0x44, 0x03, 0x33, 0xF9, 0x02, 0x7C, + 0x8F, 0x42, 0x08, 0xDD, + 0x01, 0x9F, 0x07, 0xEB, 0x44, 0x07, 0xB7, 0xF9, 0x02, 0x70, 0x8F, 0x42, + 0x01, 0xDD, 0x01, 0x27, + 0x10, 0x97, 0xB3, 0xF9, 0x02, 0x30, 0x8B, 0x42, 0x06, 0xDD, 0x01, 0x9B, + 0x03, 0xEB, 0x44, 0x03, + 0x33, 0xF9, 0x02, 0x3C, 0x8B, 0x42, 0x41, 0xDC, 0x10, 0x99, 0x59, 0xB9, + 0xBA, 0xF1, 0x01, 0x0F, + 0x0F, 0xD9, 0x0D, 0x99, 0x31, 0xF9, 0x14, 0x10, 0x81, 0x42, 0x0A, 0xDD, + 0x01, 0x99, 0x31, 0xF9, + 0x14, 0x10, 0x01, 0xE0, 0x30, 0xE0, 0x5B, 0xE0, 0x81, 0x42, 0x02, 0xDD, + 0x01, 0x21, 0x10, 0x91, + 0x15, 0x91, 0xC6, 0x4B, 0x1B, 0x78, 0x9B, 0x1E, 0x9A, 0x45, 0x09, 0xD2, + 0x82, 0x42, 0x07, 0xDD, + 0x04, 0x99, 0x31, 0xF9, 0x14, 0x10, 0x81, 0x42, 0x02, 0xDD, 0x01, 0x21, + 0x10, 0x91, 0x15, 0x91, + 0x01, 0x2C, 0x0A, 0xD9, 0x3C, 0xF9, 0x04, 0x1C, 0x81, 0x42, 0x06, 0xDD, + 0xBC, 0xF9, 0x02, 0x10, + 0x81, 0x42, 0x02, 0xDD, 0x01, 0x21, 0x10, 0x91, 0x16, 0x91, 0xAE, 0xF1, + 0x02, 0x01, 0x00, 0xE0, + 0x17, 0xE0, 0x8C, 0x42, 0x08, 0xD2, 0x86, 0x42, 0x06, 0xDD, 0xBC, 0xF9, + 0x04, 0x10, 0x81, 0x42, + 0x02, 0xDD, 0x01, 0x20, 0x16, 0x90, 0x01, 0xE0, 0x10, 0x98, 0x48, 0xB1, + 0xB0, 0x49, 0x41, 0xF2, + 0xB3, 0x50, 0x08, 0x80, 0xAF, 0x48, 0xB0, 0x49, 0x04, 0x80, 0xA1, 0xF8, + 0x00, 0xA0, 0x09, 0xE0, + 0x40, 0xB9, 0x02, 0x98, 0x30, 0xF9, 0x14, 0x10, 0x49, 0x45, 0x03, 0xDD, + 0x05, 0x99, 0x01, 0x20, + 0x08, 0x55, 0x15, 0xE0, 0x16, 0x98, 0x98, 0xB1, 0x15, 0x98, 0x88, 0xB1, + 0x13, 0x98, 0x78, 0xB1, + 0x05, 0x98, 0x01, 0x21, 0x01, 0x55, 0x12, 0x98, 0x40, 0x1C, 0x80, 0xB2, + 0x12, 0x90, 0xA3, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x4A, 0x14, 0x12, 0x98, 0x81, 0x42, 0x01, 0xD2, + 0x01, 0x20, 0x14, 0x90, + 0x64, 0x1C, 0x68, 0x78, 0xA0, 0x42, 0xBF, 0xF4, 0x2D, 0xAF, 0x97, 0x48, + 0x0D, 0x99, 0x0B, 0xF1, + 0x28, 0x0B, 0x00, 0x78, 0x0A, 0xF1, 0x01, 0x0A, 0x01, 0xEB, 0x40, 0x01, + 0x0D, 0x91, 0x03, 0x99, + 0x01, 0xEB, 0x40, 0x01, 0x03, 0x91, 0x02, 0x99, 0x01, 0xEB, 0x40, 0x01, + 0x02, 0x91, 0x01, 0x99, + 0x01, 0xEB, 0x40, 0x01, 0x01, 0x91, 0x04, 0x99, 0x01, 0xEB, 0x40, 0x00, + 0x04, 0x90, 0x05, 0x98, + 0x28, 0x30, 0x05, 0x90, 0xC2, 0x45, 0x7F, 0xF6, 0x0B, 0xAF, 0x14, 0x98, + 0x1F, 0xB0, 0xA8, 0xE5, + 0x2D, 0xE9, 0xF0, 0x47, 0x04, 0x46, 0x91, 0x42, 0x5A, 0xD0, 0x07, 0xD9, + 0x01, 0xEB, 0x02, 0x00, + 0xA0, 0xEB, 0x02, 0x01, 0xCA, 0xB2, 0xA0, 0xEB, 0x02, 0x00, 0xC1, 0xB2, + 0x01, 0xEB, 0xC1, 0x00, + 0x04, 0xEB, 0xC0, 0x01, 0x02, 0xEB, 0xC2, 0x00, 0x04, 0xEB, 0xC0, 0x00, + 0xB1, 0xF9, 0x32, 0x50, + 0xB0, 0xF9, 0x32, 0x30, 0x81, 0x46, 0x9D, 0x42, 0x00, 0xDA, 0x4B, 0x86, + 0xCB, 0x8C, 0xC5, 0x8C, + 0x2B, 0x44, 0xCB, 0x84, 0x0B, 0x8D, 0x05, 0x8D, 0x2B, 0x44, 0x0B, 0x85, + 0x4B, 0x8D, 0x45, 0x8D, + 0x2B, 0x44, 0x4B, 0x85, 0x8B, 0x69, 0x85, 0x69, 0x2B, 0x44, 0x8B, 0x61, + 0xC7, 0x69, 0xCE, 0x69, + 0xCB, 0x68, 0xD9, 0xF8, 0x0C, 0x00, 0x4F, 0xEA, 0x23, 0x4C, 0x4F, 0xEA, + 0x20, 0x48, 0x0C, 0xFB, + 0x06, 0xFC, 0xF5, 0x19, 0x07, 0xFB, 0x08, 0xCC, 0x9C, 0xFB, 0xF5, 0xFC, + 0x6C, 0xF3, 0x1F, 0x43, + 0x0F, 0xFA, 0x83, 0xFC, 0x0C, 0xFB, 0x06, 0xFC, 0x00, 0xB2, 0x07, 0xFB, + 0x00, 0xC0, 0x90, 0xFB, + 0xF5, 0xF0, 0x60, 0xF3, 0x0F, 0x03, 0xCD, 0x61, 0xCB, 0x60, 0x94, 0xF8, + 0x38, 0x04, 0x41, 0x1E, + 0x91, 0x42, 0x08, 0xD0, 0x00, 0xEB, 0xC0, 0x00, 0x04, 0xEB, 0xC0, 0x01, + 0x48, 0x46, 0x48, 0x22, + 0x48, 0x39, 0x07, 0xF0, 0xAF, 0xFA, 0x94, 0xF8, 0x38, 0x04, 0x40, 0x1E, + 0x84, 0xF8, 0x38, 0x04, + 0xBD, 0xE8, 0xF0, 0x87, 0x2D, 0xE9, 0xFE, 0x4F, 0x07, 0x46, 0x58, 0x48, + 0x8A, 0x46, 0x00, 0x25, + 0x01, 0x68, 0xB1, 0xF8, 0xEA, 0x02, 0x00, 0xFB, 0x00, 0xF9, 0x55, 0x48, + 0x00, 0x78, 0x18, 0xB1, + 0xB1, 0xF8, 0x66, 0x03, 0x00, 0xFB, 0x00, 0xF9, 0x54, 0x46, 0x4F, 0xF0, + 0x01, 0x0B, 0xB0, 0xE0, + 0x0B, 0xFA, 0x04, 0xF0, 0x26, 0x46, 0x00, 0x90, 0x66, 0xE0, 0x00, 0xBF, + 0x00, 0x99, 0x0B, 0xFA, + 0x06, 0xF0, 0x08, 0x42, 0x5F, 0xD0, 0x06, 0xEB, 0xC6, 0x00, 0x07, 0xEB, + 0xC0, 0x00, 0xC2, 0x68, + 0x20, 0x46, 0x4D, 0xE0, 0xB0, 0x42, 0x4A, 0xD0, 0x00, 0xEB, 0xC0, 0x01, + 0x07, 0xEB, 0xC1, 0x01, + 0xC9, 0x68, 0x4F, 0xEA, 0x21, 0x4C, 0xAC, 0xEB, 0x22, 0x4C, 0x89, 0x1A, + 0x0F, 0xFA, 0x8C, 0xFC, + 0x09, 0xB2, 0x6C, 0xF3, 0x1F, 0x45, 0x61, 0xF3, 0x0F, 0x05, 0x8E, 0x46, + 0x3B, 0x49, 0xCD, 0xF8, + 0x04, 0xC0, 0x09, 0x68, 0x91, 0xF8, 0xE0, 0xC2, 0xCD, 0xF8, 0x08, 0xC0, + 0x5F, 0xEA, 0x8C, 0x6C, + 0x0B, 0xD5, 0x91, 0xF8, 0xED, 0x82, 0x0E, 0xFB, 0x08, 0xFC, 0x4F, 0xF0, + 0x64, 0x08, 0x9C, 0xFB, + 0xF8, 0xF8, 0x08, 0xEB, 0x0E, 0x0C, 0x6C, 0xF3, 0x0F, 0x05, 0xDD, 0xF8, + 0x08, 0xC0, 0x5F, 0xEA, + 0xCC, 0x6C, 0x0C, 0xD5, 0x91, 0xF8, 0xED, 0x12, 0xDD, 0xF8, 0x04, 0xC0, + 0x0C, 0xFB, 0x01, 0xFC, + 0x64, 0x21, 0x9C, 0xFB, 0xF1, 0xFC, 0x01, 0x99, 0x61, 0x44, 0x61, 0xF3, + 0x1F, 0x45, 0x4F, 0xEA, + 0x25, 0x4C, 0x0C, 0xFB, 0x0C, 0xFC, 0x29, 0xB2, 0x01, 0xFB, 0x01, 0xC1, + 0x49, 0x45, 0x06, 0xD2, + 0xDD, 0xF8, 0x00, 0xC0, 0x0B, 0xFA, 0x00, 0xF1, 0x41, 0xEA, 0x0C, 0x01, + 0x00, 0x91, 0x40, 0x1C, + 0x83, 0x42, 0xAF, 0xD8, 0x04, 0x21, 0x68, 0x46, 0xF1, 0xF7, 0x3D, 0xFA, + 0x01, 0x28, 0x02, 0xD1, + 0x00, 0x98, 0x40, 0x00, 0x00, 0x90, 0x76, 0x1C, 0x97, 0xF8, 0x38, 0x34, + 0xB3, 0x42, 0x95, 0xD8, + 0x04, 0x21, 0x68, 0x46, 0xF1, 0xF7, 0x2F, 0xFA, 0x01, 0x28, 0x0B, 0xD0, + 0x04, 0x21, 0x68, 0x46, + 0xF1, 0xF7, 0x29, 0xFA, 0x97, 0xF8, 0x38, 0x64, 0xA6, 0xEB, 0x0A, 0x01, + 0x88, 0x42, 0x06, 0xD1, + 0x87, 0xF8, 0x38, 0xA4, 0xBD, 0xE8, 0xFE, 0x8F, 0x64, 0x1C, 0xE4, 0xB2, + 0x01, 0xE0, 0x00, 0x99, + 0x58, 0x46, 0x00, 0xFA, 0x04, 0xF2, 0x0A, 0x42, 0xF6, 0xD0, 0xD8, 0x46, + 0x1C, 0xE0, 0x00, 0x00, + 0x98, 0x46, 0x10, 0x00, 0x86, 0x07, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, + 0xED, 0x06, 0x10, 0x00, + 0x88, 0x07, 0x10, 0x00, 0x8A, 0x07, 0x10, 0x00, 0x8C, 0x07, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0xFD, 0x06, 0x10, 0x00, 0x00, 0x99, 0x08, 0xFA, 0x06, 0xF0, 0x08, 0x42, + 0x04, 0xD0, 0xF2, 0xB2, + 0x21, 0x46, 0x38, 0x46, 0xFF, 0xF7, 0xDC, 0xFE, 0x76, 0x1E, 0xA6, 0x42, + 0xF2, 0xD8, 0x64, 0x1C, + 0xE4, 0xB2, 0x97, 0xF8, 0x38, 0x04, 0xA0, 0x42, 0x3F, 0xF6, 0x4A, 0xAF, + 0xCA, 0xE7, 0x2D, 0xE9, + 0xFF, 0x4F, 0xFB, 0x48, 0xFB, 0x4C, 0x93, 0x46, 0x06, 0x68, 0x81, 0xB0, + 0x1D, 0x46, 0x06, 0xF5, + 0x88, 0x7A, 0x01, 0x22, 0x59, 0x46, 0x20, 0x68, 0xFE, 0xF7, 0x92, 0xFE, + 0x00, 0x95, 0xDD, 0xE9, + 0x01, 0x12, 0x5B, 0x46, 0x20, 0x68, 0xFF, 0xF7, 0xFB, 0xFC, 0x03, 0x00, + 0x4F, 0xF0, 0x01, 0x01, + 0x05, 0xD0, 0xF1, 0x48, 0x01, 0x70, 0xA8, 0x8C, 0x40, 0xF0, 0x80, 0x00, + 0xA8, 0x84, 0xEF, 0x48, + 0x00, 0x78, 0x50, 0xB1, 0x4B, 0xB9, 0x95, 0xF8, 0x24, 0x00, 0x10, 0xF0, + 0x06, 0x0F, 0x04, 0xD1, + 0x59, 0x46, 0x28, 0x46, 0xFE, 0xF7, 0xA8, 0xFE, 0x03, 0x46, 0x00, 0x20, + 0x86, 0xF8, 0x0E, 0x01, + 0xDB, 0xF8, 0x00, 0x00, 0x30, 0x60, 0xE3, 0x48, 0x00, 0x22, 0x31, 0x46, + 0x00, 0x68, 0xFE, 0xF7, + 0x3F, 0xFF, 0x96, 0xF8, 0x0E, 0x01, 0x00, 0x24, 0x01, 0x28, 0x79, 0xD9, + 0xFC, 0xF7, 0x61, 0xF9, + 0x81, 0x46, 0xFC, 0xF7, 0x5C, 0xF9, 0x80, 0x46, 0xDB, 0xF8, 0x00, 0x20, + 0xDD, 0xE9, 0x01, 0x01, + 0x00, 0x92, 0xDB, 0x4B, 0x6A, 0x46, 0xFE, 0xF7, 0x0A, 0xFE, 0x60, 0xB1, + 0x69, 0x46, 0xD8, 0x48, + 0xFE, 0xF7, 0x9E, 0xFD, 0x2A, 0x46, 0x69, 0x46, 0xD5, 0x48, 0xFD, 0xF7, + 0xD8, 0xFA, 0xE9, 0x68, + 0x69, 0x61, 0xE9, 0x69, 0x29, 0x62, 0x01, 0x27, 0x2F, 0xE0, 0x48, 0x22, + 0x29, 0x46, 0x50, 0x46, + 0x07, 0xF0, 0x78, 0xF9, 0xCF, 0x49, 0x06, 0xEB, 0x47, 0x00, 0x09, 0x68, + 0xB0, 0xF8, 0xB4, 0x20, + 0x91, 0xF8, 0xEC, 0x12, 0x8A, 0x42, 0x1F, 0xD9, 0xBA, 0xF8, 0x24, 0x10, + 0x41, 0xF0, 0x10, 0x02, + 0xAA, 0xF8, 0x24, 0x20, 0xB0, 0xF8, 0xB4, 0x10, 0xAA, 0xF8, 0x26, 0x10, + 0x06, 0xEB, 0x87, 0x00, + 0x51, 0x46, 0x00, 0x90, 0xFF, 0xF7, 0x12, 0xF9, 0xBE, 0x48, 0xF9, 0xB2, + 0x53, 0x46, 0x00, 0x9A, + 0x00, 0x68, 0xFD, 0xF7, 0xF6, 0xFE, 0xBB, 0x48, 0xF9, 0xB2, 0x53, 0x46, + 0x00, 0x9A, 0x00, 0x68, + 0xFD, 0xF7, 0x6E, 0xFE, 0x64, 0x1C, 0xE4, 0xB2, 0x7F, 0x1C, 0x96, 0xF8, + 0x0E, 0x01, 0xB8, 0x42, + 0xCB, 0xD2, 0xB8, 0x4E, 0x30, 0x68, 0x90, 0xF8, 0xE0, 0x02, 0x00, 0x07, + 0x0A, 0xD5, 0x01, 0x2C, + 0x08, 0xD9, 0x49, 0x46, 0x40, 0x46, 0xFF, 0xF7, 0x95, 0xFE, 0xFC, 0xF7, + 0x02, 0xF9, 0xA0, 0xEB, + 0x09, 0x00, 0xC4, 0xB2, 0x31, 0x68, 0x91, 0xF8, 0xE0, 0x02, 0x00, 0x06, + 0x13, 0xD5, 0x20, 0x46, + 0x0F, 0xE0, 0x00, 0xBF, 0x09, 0xEB, 0x00, 0x02, 0xD2, 0xB2, 0x02, 0xEB, + 0xC2, 0x03, 0x08, 0xEB, + 0xC3, 0x02, 0x91, 0xF8, 0x07, 0x33, 0xD2, 0x8C, 0x9A, 0x42, 0x02, 0xD9, + 0x88, 0xF8, 0x38, 0x94, + 0x05, 0xE0, 0x40, 0x1E, 0xEE, 0xD2, 0x01, 0x2C, 0x0A, 0xD0, 0x00, 0x2C, + 0x0E, 0xD1, 0xDD, 0xE9, + 0x01, 0x01, 0x05, 0xB0, 0x2B, 0x46, 0x5A, 0x46, 0xBD, 0xE8, 0xF0, 0x4F, + 0xFD, 0xF7, 0x30, 0xBE, + 0x98, 0xF8, 0x38, 0x04, 0x40, 0x1E, 0x88, 0xF8, 0x38, 0x04, 0xF0, 0xE7, + 0x05, 0xB0, 0xBD, 0xE8, + 0xF0, 0x8F, 0x2D, 0xE9, 0xFF, 0x4F, 0x97, 0x48, 0x81, 0xB0, 0x00, 0x68, + 0x90, 0xF8, 0xE1, 0x02, + 0xC0, 0x07, 0xF3, 0xD0, 0xA8, 0x21, 0x04, 0x98, 0x07, 0xF0, 0x58, 0xF9, + 0x01, 0x25, 0x44, 0xE0, + 0x03, 0x98, 0x00, 0xEB, 0x85, 0x00, 0x82, 0x46, 0x84, 0x78, 0x90, 0xF8, + 0x03, 0x90, 0x8E, 0x48, + 0x00, 0x78, 0x40, 0x1E, 0x84, 0x42, 0x01, 0xDA, 0x64, 0x1C, 0xE4, 0xB2, + 0xB9, 0xF1, 0x00, 0x0F, + 0x03, 0xD0, 0xA9, 0xF1, 0x01, 0x00, 0x00, 0xF0, 0xFF, 0x09, 0x21, 0x46, + 0x01, 0x98, 0x07, 0xF0, + 0x1F, 0xFA, 0x83, 0x46, 0xA0, 0x46, 0x24, 0xE0, 0x03, 0x98, 0x04, 0x99, + 0x10, 0xF8, 0x25, 0x40, + 0x01, 0xEB, 0xC8, 0x00, 0x00, 0x90, 0x12, 0xE0, 0x1B, 0xF8, 0x04, 0x00, + 0xA8, 0x42, 0x0C, 0xD1, + 0x00, 0x98, 0x22, 0x46, 0x00, 0x21, 0xD0, 0xE9, 0x00, 0x67, 0x01, 0x20, + 0x07, 0xF0, 0x4E, 0xF8, + 0x06, 0x43, 0x00, 0x98, 0x0F, 0x43, 0xC0, 0xE9, 0x00, 0x67, 0x64, 0x1C, + 0xE4, 0xB2, 0x9A, 0xF8, + 0x01, 0x00, 0xA0, 0x42, 0xE8, 0xD2, 0x08, 0xF1, 0x01, 0x00, 0x0B, 0xF1, + 0x28, 0x0B, 0x00, 0xF0, + 0xFF, 0x08, 0xC8, 0x45, 0xD8, 0xD9, 0x6D, 0x1C, 0xED, 0xB2, 0x02, 0x98, + 0x85, 0x42, 0xB7, 0xD9, + 0x00, 0x21, 0x6D, 0x4E, 0x13, 0xE0, 0x04, 0x98, 0x00, 0xEB, 0xC1, 0x05, + 0x01, 0xF1, 0x01, 0x01, + 0xD5, 0xE9, 0x00, 0x32, 0xDC, 0x18, 0x42, 0xEB, 0x02, 0x00, 0x52, 0x08, + 0x4F, 0xEA, 0x33, 0x03, + 0x04, 0xEA, 0x03, 0x04, 0x00, 0xEA, 0x02, 0x00, 0xC5, 0xE9, 0x00, 0x40, + 0xC9, 0xB2, 0x30, 0x78, + 0x81, 0x42, 0xE8, 0xD3, 0x8A, 0xE7, 0xF0, 0xB4, 0x60, 0x4D, 0x00, 0x24, + 0x2C, 0x80, 0x60, 0x4D, + 0x2C, 0x80, 0x60, 0x4D, 0x2C, 0x80, 0x60, 0x4D, 0x2C, 0x80, 0x14, 0x68, + 0xC3, 0xF8, 0x3A, 0x40, + 0x58, 0x4C, 0x25, 0x68, 0x95, 0xF8, 0xE0, 0x42, 0xA6, 0x07, 0x13, 0xD4, + 0x93, 0xF8, 0x40, 0x60, + 0x01, 0x2E, 0x0F, 0xD0, 0x66, 0x07, 0x13, 0xD5, 0x64, 0x06, 0x09, 0xD5, + 0x57, 0x4C, 0x64, 0x78, + 0x5C, 0xB1, 0xB5, 0xF8, 0xF0, 0x42, 0x56, 0x4D, 0x64, 0x43, 0x2D, 0x68, + 0xA5, 0x42, 0x07, 0xDC, + 0xF0, 0xBC, 0x94, 0xE6, 0xF0, 0xBC, 0xFF, 0xF7, 0x73, 0xBA, 0xB5, 0xF8, + 0xEE, 0x42, 0xF2, 0xE7, + 0xF0, 0xBC, 0xFD, 0xF7, 0x85, 0xBD, 0x2D, 0xE9, 0xFF, 0x4F, 0x94, 0x78, + 0xD7, 0x78, 0x15, 0x78, + 0x56, 0x78, 0x81, 0xB0, 0x98, 0x46, 0x82, 0x46, 0x04, 0xB9, 0x01, 0x24, + 0x42, 0x48, 0x00, 0x78, + 0x40, 0x1E, 0x87, 0x42, 0x01, 0xD1, 0x7F, 0x1E, 0xFF, 0xB2, 0x05, 0xB9, + 0x01, 0x25, 0xDF, 0xF8, + 0x14, 0xB1, 0x9B, 0xF8, 0x00, 0x00, 0x40, 0x1E, 0x86, 0x42, 0x01, 0xD1, + 0x76, 0x1E, 0xF6, 0xB2, + 0x60, 0x1E, 0xC1, 0xB2, 0xD8, 0xF8, 0x08, 0x00, 0x07, 0xF0, 0x88, 0xF9, + 0x00, 0x90, 0x21, 0x46, + 0xD8, 0xF8, 0x08, 0x00, 0x07, 0xF0, 0x82, 0xF9, 0x81, 0x46, 0x60, 0x1C, + 0xC1, 0xB2, 0xD8, 0xF8, + 0x08, 0x00, 0x07, 0xF0, 0x7B, 0xF9, 0x80, 0x46, 0x21, 0x46, 0x50, 0x46, + 0x07, 0xF0, 0x70, 0xF9, + 0x35, 0xE0, 0x2C, 0x4A, 0x29, 0x46, 0xD2, 0xF8, 0x00, 0xA0, 0x24, 0xE0, + 0x43, 0x5C, 0x02, 0x9A, + 0x93, 0x42, 0x1E, 0xD1, 0x39, 0xF8, 0x11, 0x30, 0x9A, 0xF8, 0x27, 0x24, + 0x1A, 0x44, 0x00, 0x9B, + 0x12, 0xB2, 0x03, 0xEB, 0x41, 0x03, 0x33, 0xF9, 0x02, 0xCC, 0x94, 0x45, + 0x05, 0xDD, 0x08, 0xEB, + 0x41, 0x0C, 0xBC, 0xF9, 0x02, 0xC0, 0x94, 0x45, 0x09, 0xDC, 0xB3, 0xF9, + 0x02, 0x30, 0x93, 0x42, + 0x07, 0xDD, 0x08, 0xEB, 0x41, 0x03, 0x33, 0xF9, 0x02, 0x3C, 0x93, 0x42, + 0x01, 0xDD, 0x01, 0x20, + 0xFC, 0xE6, 0x49, 0x1C, 0xC9, 0xB2, 0xB1, 0x42, 0xD8, 0xD9, 0xCD, 0xF8, + 0x00, 0x90, 0x9B, 0xF8, + 0x00, 0x20, 0x64, 0x1C, 0xC1, 0x46, 0x08, 0xEB, 0x42, 0x08, 0xE4, 0xB2, + 0x28, 0x30, 0xBC, 0x42, + 0xC7, 0xD9, 0x00, 0x20, 0xEA, 0xE6, 0x2D, 0xE9, 0xF8, 0x4F, 0x4F, 0xF0, + 0x00, 0x0A, 0x89, 0x46, + 0x04, 0x46, 0x01, 0x26, 0x57, 0x46, 0xD0, 0x46, 0x85, 0x78, 0x46, 0xE0, + 0x29, 0x46, 0xD9, 0xF8, + 0x08, 0x00, 0x07, 0xF0, 0x2B, 0xF9, 0x02, 0x46, 0x00, 0x20, 0x21, 0x78, + 0x63, 0x78, 0x20, 0xE0, + 0x6C, 0x06, 0x10, 0x00, 0x54, 0x06, 0x10, 0x00, 0x34, 0x06, 0x10, 0x00, + 0xA4, 0x06, 0x10, 0x00, + 0xF0, 0x45, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xED, 0x06, 0x10, 0x00, + 0x86, 0x07, 0x10, 0x00, + 0x88, 0x07, 0x10, 0x00, 0x8A, 0x07, 0x10, 0x00, 0x8C, 0x07, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, + 0x24, 0x07, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, 0x32, 0xF9, 0x11, 0xC0, + 0x49, 0x1C, 0x60, 0x44, + 0xC9, 0xB2, 0x8B, 0x42, 0xF8, 0xD2, 0xA1, 0x78, 0x4A, 0x1C, 0xAA, 0x42, + 0x10, 0xD2, 0x46, 0x4A, + 0x12, 0x68, 0xB2, 0xF8, 0x28, 0x34, 0x03, 0xEB, 0x08, 0x02, 0xBA, 0x42, + 0x01, 0xDA, 0x82, 0x42, + 0x33, 0xDB, 0x89, 0x1C, 0xA9, 0x42, 0x03, 0xD2, 0x52, 0x45, 0x01, 0xDA, + 0x82, 0x42, 0x2C, 0xDB, + 0xBA, 0x46, 0x47, 0x46, 0x6D, 0x1C, 0x80, 0x46, 0xED, 0xB2, 0xE0, 0x78, + 0xA8, 0x42, 0xB5, 0xD2, + 0x00, 0x20, 0x00, 0x90, 0x82, 0x46, 0x83, 0x46, 0x25, 0x78, 0x2E, 0xE0, + 0x4F, 0xF0, 0x00, 0x08, + 0xA7, 0x78, 0x09, 0xE0, 0x39, 0x46, 0xD9, 0xF8, 0x08, 0x00, 0x07, 0xF0, + 0xD7, 0xF8, 0x30, 0xF9, + 0x15, 0x10, 0x7F, 0x1C, 0x88, 0x44, 0xFF, 0xB2, 0xE0, 0x78, 0xB8, 0x42, + 0xF2, 0xD2, 0x20, 0x78, + 0x41, 0x1C, 0xA9, 0x42, 0x13, 0xD2, 0x2C, 0x49, 0x09, 0x68, 0xB1, 0xF8, + 0x28, 0x24, 0x02, 0xEB, + 0x0B, 0x01, 0x51, 0x45, 0x03, 0xDA, 0x41, 0x45, 0x01, 0xDA, 0x00, 0x26, + 0x10, 0xE0, 0x80, 0x1C, + 0xA8, 0x42, 0x04, 0xD2, 0x00, 0x98, 0x81, 0x42, 0x01, 0xDA, 0x41, 0x45, + 0xF5, 0xDB, 0xCD, 0xF8, + 0x00, 0xA0, 0xDA, 0x46, 0x6D, 0x1C, 0xC3, 0x46, 0xED, 0xB2, 0x60, 0x78, + 0xA8, 0x42, 0xCD, 0xD2, + 0x30, 0x46, 0xBD, 0xE8, 0xF8, 0x8F, 0x2D, 0xE9, 0xF0, 0x41, 0x07, 0x46, + 0x98, 0x8C, 0x14, 0x46, + 0x00, 0x26, 0x1D, 0x46, 0xC2, 0x05, 0x02, 0xD5, 0x01, 0x20, 0xBD, 0xE8, + 0xF0, 0x81, 0x00, 0x06, + 0x27, 0xD4, 0x15, 0x48, 0xEA, 0x8C, 0x00, 0x68, 0x90, 0xF8, 0x23, 0x34, + 0x9A, 0x42, 0x20, 0xD3, + 0xB0, 0xF8, 0x24, 0x34, 0xAA, 0x69, 0x9A, 0x42, 0x1B, 0xDC, 0x62, 0x78, + 0x23, 0x78, 0x90, 0xF8, + 0x26, 0x04, 0xD2, 0x1A, 0x52, 0x1C, 0x82, 0x42, 0x13, 0xDC, 0xE2, 0x78, + 0xA3, 0x78, 0xD2, 0x1A, + 0x52, 0x1C, 0x82, 0x42, 0x0D, 0xDC, 0x2B, 0x46, 0x22, 0x46, 0x38, 0x46, + 0xFF, 0xF7, 0xD3, 0xFE, + 0x01, 0x28, 0x06, 0xD1, 0x29, 0x46, 0x20, 0x46, 0xFF, 0xF7, 0x3D, 0xFF, + 0x01, 0x28, 0x00, 0xD1, + 0x01, 0x26, 0x30, 0x46, 0xD1, 0xE7, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x70, 0x47, 0xF0, 0xB5, + 0x99, 0x4B, 0x02, 0x46, 0x0C, 0x46, 0x1F, 0x78, 0x98, 0x4B, 0x1E, 0x68, + 0x98, 0x4B, 0x1D, 0x78, + 0x19, 0xE0, 0x2B, 0x46, 0x11, 0xE0, 0x00, 0xBF, 0x34, 0xF8, 0x13, 0xC0, + 0x32, 0xF8, 0x13, 0xE0, + 0xAC, 0xEB, 0x0E, 0x0C, 0xB6, 0xF9, 0x46, 0xE0, 0x0F, 0xFA, 0x8C, 0xFC, + 0x1E, 0xEB, 0x0C, 0x0F, + 0x22, 0xD4, 0xB6, 0xF8, 0x48, 0xE0, 0xE6, 0x45, 0x1E, 0xDB, 0x5B, 0x1E, + 0xEC, 0xD1, 0x02, 0xEB, + 0x45, 0x02, 0x04, 0xEB, 0x45, 0x04, 0x7F, 0x1E, 0xE3, 0xD2, 0x96, 0xF8, + 0x44, 0x20, 0x89, 0x4B, + 0x02, 0xF0, 0x0F, 0x02, 0xC2, 0xF1, 0x10, 0x04, 0xB3, 0xF9, 0x00, 0x30, + 0x0A, 0xE0, 0x00, 0xBF, + 0x31, 0xF9, 0x13, 0x50, 0x30, 0xF9, 0x13, 0x60, 0x55, 0x43, 0x06, 0xFB, + 0x04, 0x55, 0x2D, 0x11, + 0x21, 0xF8, 0x13, 0x50, 0x5B, 0x1E, 0xF3, 0xD2, 0xF0, 0xBD, 0xF0, 0xB5, + 0x14, 0x46, 0x05, 0x9F, + 0x0B, 0xE0, 0x00, 0xBF, 0x31, 0xF9, 0x14, 0x50, 0x30, 0xF9, 0x14, 0x60, + 0x05, 0xEB, 0x03, 0x0C, + 0xB4, 0x45, 0x19, 0xDB, 0xED, 0x1B, 0xB5, 0x42, 0x16, 0xDC, 0x64, 0x1E, + 0xF2, 0xD1, 0x73, 0x4B, + 0x1B, 0x68, 0x93, 0xF8, 0x45, 0x30, 0x1B, 0x09, 0xC3, 0xF1, 0x10, 0x04, + 0x0A, 0xE0, 0x00, 0xBF, + 0x31, 0xF9, 0x12, 0x50, 0x30, 0xF9, 0x12, 0x60, 0x5D, 0x43, 0x06, 0xFB, + 0x04, 0x55, 0x2D, 0x11, + 0x21, 0xF8, 0x12, 0x50, 0x52, 0x1E, 0xF3, 0xD2, 0xF0, 0xBD, 0x2D, 0xE9, + 0xF0, 0x43, 0x81, 0x46, + 0x66, 0x48, 0x69, 0x4C, 0x00, 0x68, 0x30, 0xF9, 0x5B, 0x6F, 0xB0, 0xF9, + 0x02, 0x70, 0x10, 0xF8, + 0x01, 0x0C, 0x00, 0xF0, 0x0F, 0x03, 0xC3, 0xF1, 0x10, 0x08, 0x00, 0x20, + 0x17, 0xE0, 0x00, 0xBF, + 0x34, 0xF9, 0x10, 0x20, 0x39, 0xF9, 0x10, 0x50, 0x02, 0xEB, 0x06, 0x0C, + 0x65, 0x45, 0x0C, 0xDC, + 0xA2, 0xEB, 0x07, 0x0C, 0x65, 0x45, 0x08, 0xDB, 0x5A, 0x43, 0x05, 0xFB, + 0x08, 0x22, 0xD5, 0x17, + 0x02, 0xEB, 0x15, 0x72, 0x12, 0x11, 0x24, 0xF8, 0x10, 0x20, 0x40, 0x1C, + 0xC0, 0xB2, 0x88, 0x42, + 0xE6, 0xD3, 0xBD, 0xE8, 0xF0, 0x83, 0x2D, 0xE9, 0xF8, 0x4F, 0x0D, 0x46, + 0x04, 0x46, 0x01, 0xF0, + 0x7F, 0xF8, 0x00, 0x28, 0x5B, 0xD1, 0xE8, 0x07, 0x08, 0xD0, 0x50, 0x48, + 0x50, 0x49, 0x00, 0x78, + 0x09, 0x68, 0x01, 0x28, 0x20, 0x68, 0x2D, 0xD0, 0x00, 0xF0, 0x53, 0xF8, + 0x47, 0x4E, 0xE8, 0x06, + 0x17, 0xD5, 0x30, 0x68, 0xB0, 0xF9, 0x50, 0x10, 0x00, 0x91, 0x43, 0x49, + 0xB0, 0xF9, 0x4E, 0x30, + 0x20, 0x69, 0x0A, 0x78, 0x47, 0x49, 0xFF, 0xF7, 0x88, 0xFF, 0x30, 0x68, + 0xB0, 0xF9, 0x54, 0x10, + 0x00, 0x91, 0x3F, 0x49, 0xB0, 0xF9, 0x52, 0x30, 0x60, 0x69, 0x0A, 0x78, + 0x42, 0x49, 0xFF, 0xF7, + 0x7C, 0xFF, 0xA8, 0x07, 0x2B, 0xD5, 0x36, 0x68, 0x41, 0x49, 0xA7, 0x68, + 0x96, 0xF8, 0x45, 0x00, + 0xDF, 0xF8, 0xF8, 0x90, 0x00, 0xF0, 0x0F, 0x03, 0xC3, 0xF1, 0x10, 0x0A, + 0x00, 0x20, 0xB1, 0xF9, + 0x00, 0xC0, 0x1A, 0xE0, 0xFF, 0xF7, 0x2B, 0xFF, 0xD0, 0xE7, 0x00, 0xBF, + 0x39, 0xF9, 0x10, 0x10, + 0xB6, 0xF9, 0x56, 0x80, 0x37, 0xF9, 0x10, 0x20, 0x88, 0x44, 0x90, 0x45, + 0x0B, 0xDB, 0xB6, 0xF9, + 0x58, 0x80, 0xA1, 0xEB, 0x08, 0x08, 0x90, 0x45, 0x05, 0xDC, 0x59, 0x43, + 0x02, 0xFB, 0x0A, 0x11, + 0x0A, 0x11, 0x29, 0xF8, 0x10, 0x20, 0x40, 0x1C, 0x00, 0xB2, 0x60, 0x45, + 0xE6, 0xDB, 0xA8, 0x05, + 0x05, 0xD5, 0x94, 0xF8, 0x32, 0x10, 0xA0, 0x69, 0xBD, 0xE8, 0xF8, 0x4F, + 0x6D, 0xE7, 0xBD, 0xE8, + 0xF8, 0x8F, 0x2D, 0xE9, 0xF0, 0x43, 0x81, 0x46, 0x26, 0x48, 0x03, 0x78, + 0x1B, 0x48, 0x05, 0x2B, + 0x00, 0x68, 0x90, 0xF8, 0x44, 0x20, 0x0C, 0xD0, 0x30, 0xF9, 0x46, 0x5F, + 0x02, 0xF0, 0x0F, 0x03, + 0xB0, 0xF9, 0x02, 0x60, 0x17, 0x48, 0xC3, 0xF1, 0x10, 0x04, 0xB0, 0xF9, + 0x00, 0x00, 0x02, 0x46, + 0x11, 0xE0, 0x30, 0xF9, 0x4A, 0x5F, 0x13, 0x09, 0xB0, 0xF9, 0x02, 0x60, + 0xF2, 0xE7, 0x00, 0xBF, + 0x31, 0xF9, 0x12, 0x70, 0x39, 0xF9, 0x12, 0xC0, 0x07, 0xEB, 0x05, 0x08, + 0xE0, 0x45, 0x11, 0xDB, + 0xBF, 0x1B, 0x67, 0x45, 0x0E, 0xDC, 0x52, 0x1E, 0xF2, 0xD2, 0x09, 0xE0, + 0x31, 0xF9, 0x10, 0x20, + 0x39, 0xF9, 0x10, 0x50, 0x5A, 0x43, 0x05, 0xFB, 0x04, 0x22, 0x12, 0x11, + 0x21, 0xF8, 0x10, 0x20, + 0x40, 0x1E, 0xF3, 0xD2, 0x5D, 0xE7, 0x00, 0x00, 0xED, 0x06, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0xEE, 0x06, 0x10, 0x00, 0xFE, 0x06, 0x10, 0x00, 0xFC, 0x4A, 0x01, 0x20, + 0xF3, 0x06, 0x10, 0x00, + 0x1C, 0x07, 0x10, 0x00, 0x7E, 0x4A, 0x01, 0x20, 0xA8, 0x4A, 0x01, 0x20, + 0xF4, 0x4A, 0x01, 0x20, + 0x00, 0x07, 0x10, 0x00, 0xEC, 0x06, 0x10, 0x00, 0x87, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x90, 0x02, + 0x40, 0x07, 0x07, 0xD5, 0x85, 0x48, 0x86, 0x49, 0xC0, 0x78, 0x09, 0x78, + 0x88, 0x42, 0x01, 0xD0, + 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x7F, 0x48, 0x10, 0xB5, + 0x00, 0x68, 0x90, 0xF8, + 0x90, 0x12, 0x89, 0x07, 0x27, 0xD5, 0x7F, 0x49, 0x0A, 0x78, 0x52, 0x1C, + 0xD2, 0xB2, 0x0A, 0x70, + 0x90, 0xF8, 0x92, 0x32, 0x93, 0x42, 0x1E, 0xD2, 0x00, 0x22, 0x0A, 0x70, + 0x90, 0xF8, 0x50, 0x12, + 0x03, 0x24, 0xC9, 0x07, 0x03, 0xD1, 0x90, 0xF8, 0x80, 0x02, 0xC0, 0x07, + 0x00, 0xD0, 0x0B, 0x24, + 0xEF, 0xF7, 0x36, 0xFE, 0x74, 0x48, 0x01, 0x68, 0x21, 0x43, 0x01, 0x60, + 0xEF, 0xF7, 0x2E, 0xFE, + 0x10, 0x21, 0x05, 0x20, 0x02, 0xF0, 0x6F, 0xF9, 0xBD, 0xE8, 0x10, 0x40, + 0x4F, 0xF4, 0x80, 0x71, + 0x00, 0x20, 0xEF, 0xF7, 0x66, 0xBF, 0x10, 0xBD, 0x68, 0x48, 0x6C, 0x49, + 0x4F, 0xF0, 0x00, 0x02, + 0x43, 0x78, 0x09, 0x78, 0x0B, 0x43, 0x67, 0x49, 0x08, 0xD1, 0x4B, 0x78, + 0x5B, 0x1C, 0xDB, 0xB2, + 0x4B, 0x70, 0x05, 0x2B, 0x03, 0xD9, 0x01, 0x23, 0x43, 0x70, 0x83, 0x70, + 0x4A, 0x70, 0x70, 0x47, + 0x2D, 0xE9, 0xF3, 0x4F, 0x62, 0x48, 0x00, 0x27, 0xDF, 0xF8, 0x88, 0xA1, + 0x90, 0xF8, 0x00, 0x80, + 0x59, 0x48, 0x81, 0xB0, 0x3C, 0x46, 0x00, 0x68, 0xB9, 0x46, 0x90, 0xF8, + 0x90, 0x02, 0xC0, 0x07, + 0x1A, 0xD0, 0x00, 0x26, 0x4F, 0xF0, 0x01, 0x0B, 0x01, 0x9D, 0x12, 0xE0, + 0x28, 0x46, 0x02, 0x99, + 0x00, 0xF0, 0x32, 0xF8, 0x10, 0xF0, 0x01, 0x0F, 0x05, 0xD0, 0x0B, 0xFA, + 0x06, 0xF0, 0x38, 0x43, + 0x64, 0x1C, 0xC7, 0xB2, 0xE4, 0xB2, 0xBA, 0xF9, 0x00, 0x00, 0x76, 0x1C, + 0x05, 0xEB, 0x40, 0x05, + 0x36, 0xB2, 0x46, 0x45, 0xEA, 0xDB, 0x01, 0xE0, 0x44, 0x46, 0xFF, 0x27, + 0x4E, 0x48, 0x07, 0x70, + 0x4C, 0xB1, 0x00, 0x94, 0xBA, 0xF8, 0x00, 0x00, 0x3B, 0x46, 0x82, 0xB2, + 0x41, 0x46, 0x01, 0x98, + 0x00, 0xF0, 0x45, 0xF8, 0x07, 0xE0, 0x49, 0x48, 0xB0, 0xF9, 0x00, 0x10, + 0x03, 0x20, 0x02, 0xF0, + 0x12, 0xF9, 0x4F, 0xF0, 0x01, 0x09, 0x48, 0x46, 0xBD, 0xE8, 0xFE, 0x8F, + 0x70, 0x47, 0x3D, 0x48, + 0x00, 0x21, 0x01, 0x70, 0x41, 0x70, 0x70, 0x47, 0x70, 0xB5, 0x37, 0x4A, + 0x3B, 0x4C, 0x12, 0x68, + 0x24, 0x78, 0xB2, 0xF9, 0x93, 0x32, 0x0C, 0xB1, 0xB2, 0xF9, 0x99, 0x32, + 0x33, 0x4C, 0x64, 0x78, + 0x01, 0x2C, 0x02, 0xD0, 0x02, 0x2C, 0x03, 0xD0, 0x04, 0xE0, 0xB2, 0xF9, + 0x95, 0x32, 0x01, 0xE0, + 0xB2, 0xF9, 0x97, 0x32, 0x33, 0x4A, 0x36, 0x4C, 0xB2, 0xF9, 0x00, 0x20, + 0x25, 0x78, 0x12, 0xE0, + 0x30, 0xF9, 0x12, 0x40, 0x31, 0xF9, 0x12, 0x60, 0xA4, 0x1B, 0x00, 0xD5, + 0x64, 0x42, 0x24, 0xB2, + 0x9C, 0x42, 0x08, 0xDD, 0x92, 0xFB, 0xF5, 0xF6, 0x05, 0xFB, 0x16, 0x26, + 0x1E, 0xB1, 0x2B, 0x48, + 0x04, 0x80, 0x00, 0x20, 0x70, 0xBD, 0x52, 0x1E, 0xEA, 0xD2, 0x01, 0x20, + 0x70, 0xBD, 0x2D, 0xE9, + 0xF0, 0x03, 0x06, 0x9F, 0x00, 0x2F, 0x19, 0xD0, 0x01, 0x25, 0x01, 0x2F, + 0x02, 0xD0, 0x14, 0x46, + 0xA9, 0x46, 0x2E, 0xE0, 0x00, 0x24, 0x0F, 0xE0, 0x05, 0xFA, 0x04, 0xF6, + 0x1E, 0x42, 0x0A, 0xD0, + 0x00, 0x2C, 0x0B, 0xD0, 0x53, 0x00, 0x62, 0x43, 0xBD, 0xE8, 0xF0, 0x03, + 0x00, 0xEB, 0x42, 0x01, + 0x1A, 0x46, 0x06, 0xF0, 0xAA, 0xBC, 0x64, 0x1C, 0x8C, 0x42, 0xED, 0xDB, + 0xBD, 0xE8, 0xF0, 0x03, + 0x70, 0x47, 0x00, 0xBF, 0x00, 0x26, 0x00, 0xEB, 0x44, 0x0C, 0x35, 0x46, + 0x0B, 0xE0, 0x00, 0xBF, + 0x09, 0xFA, 0x05, 0xF8, 0x18, 0xEA, 0x03, 0x0F, 0x02, 0xD0, 0xBC, 0xF9, + 0x00, 0x80, 0x46, 0x44, + 0x0C, 0xEB, 0x42, 0x0C, 0x6D, 0x1C, 0x8D, 0x42, 0xF2, 0xDB, 0x96, 0xFB, + 0xF7, 0xF5, 0x20, 0xF8, + 0x14, 0x50, 0x64, 0x1E, 0xE6, 0xD2, 0xE1, 0xE7, 0x4C, 0x07, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, + 0xEF, 0x06, 0x10, 0x00, 0x70, 0x06, 0x10, 0x00, 0x54, 0x07, 0x10, 0x00, + 0x74, 0x05, 0x10, 0x00, + 0xF0, 0x06, 0x10, 0x00, 0xFE, 0x06, 0x10, 0x00, 0x75, 0x06, 0x10, 0x00, + 0x7A, 0x06, 0x10, 0x00, + 0xEE, 0x06, 0x10, 0x00, 0x10, 0xB5, 0xF6, 0xF7, 0x3D, 0xFC, 0xF7, 0xF7, + 0xC3, 0xF8, 0xBD, 0xE8, + 0x10, 0x40, 0xF5, 0xF7, 0x9F, 0xBB, 0x2D, 0xE9, 0xF0, 0x47, 0x81, 0x46, + 0x1F, 0x46, 0x90, 0x46, + 0x0E, 0x46, 0x03, 0x20, 0x08, 0x9D, 0xEF, 0xF7, 0x4C, 0xFF, 0x5C, 0x48, + 0x01, 0x68, 0x48, 0x46, + 0xFF, 0xF7, 0x16, 0xFF, 0x04, 0x46, 0x03, 0x20, 0xEF, 0xF7, 0x5E, 0xFF, + 0x64, 0xB1, 0xFF, 0xF7, + 0xFB, 0xFE, 0xFF, 0xF7, 0xC9, 0xFE, 0x31, 0x46, 0x48, 0x46, 0xFF, 0xF7, + 0x4F, 0xFF, 0x54, 0x48, + 0x04, 0x70, 0x20, 0x46, 0xBD, 0xE8, 0xF0, 0x87, 0xFF, 0xF7, 0x49, 0xFF, + 0x16, 0xB1, 0x30, 0x46, + 0x00, 0xF0, 0xE8, 0xFC, 0x65, 0xB1, 0x4F, 0x48, 0x01, 0x78, 0x28, 0x46, + 0xF6, 0xF7, 0x31, 0xFC, + 0x4D, 0x48, 0x80, 0x78, 0x20, 0xB1, 0x4D, 0x48, 0x01, 0x68, 0x21, 0xF0, + 0x30, 0x01, 0x01, 0x60, + 0x06, 0xF0, 0x6C, 0xFD, 0x05, 0x46, 0xFF, 0xF7, 0x97, 0xFE, 0x50, 0xEA, + 0x05, 0x04, 0xDA, 0xD1, + 0x3A, 0x46, 0x41, 0x46, 0x48, 0x46, 0x00, 0xF0, 0x32, 0xF8, 0x04, 0x46, + 0xD3, 0xE7, 0x10, 0xB5, + 0xF8, 0xF7, 0x5B, 0xFB, 0xFD, 0xF7, 0x1F, 0xFF, 0xFB, 0xF7, 0x28, 0xFB, + 0xFF, 0xF7, 0xAA, 0xFF, + 0xFF, 0xF7, 0x1D, 0xFF, 0xFC, 0xF7, 0xB3, 0xFA, 0x39, 0x49, 0x00, 0x20, + 0x08, 0x70, 0x48, 0x70, + 0x88, 0x80, 0xC8, 0x80, 0x88, 0x70, 0x88, 0x60, 0xC8, 0x60, 0x08, 0x61, + 0x14, 0x31, 0x08, 0x70, + 0x88, 0x70, 0x37, 0x48, 0x00, 0x68, 0x10, 0xF8, 0x30, 0x2F, 0x4A, 0x70, + 0x40, 0x78, 0xC8, 0x70, + 0x10, 0xBD, 0x10, 0xB5, 0xF8, 0xF7, 0x47, 0xFB, 0xFD, 0xF7, 0x10, 0xFF, + 0x00, 0xF0, 0x15, 0xFD, + 0xF7, 0xF7, 0x5D, 0xF8, 0x2C, 0x48, 0x00, 0x21, 0x41, 0x70, 0x81, 0x70, + 0x10, 0xBD, 0xF8, 0xB5, + 0x07, 0x46, 0x00, 0x24, 0x15, 0x46, 0x0E, 0x46, 0x8D, 0xF8, 0x00, 0x40, + 0x02, 0x20, 0xEF, 0xF7, + 0xD8, 0xFE, 0x2A, 0x46, 0x31, 0x46, 0x38, 0x46, 0xF8, 0xF7, 0x4F, 0xFA, + 0x25, 0x49, 0x01, 0x28, + 0xCA, 0x78, 0x60, 0xF3, 0x03, 0x02, 0xCA, 0x70, 0x2A, 0xD0, 0x02, 0x28, + 0x2D, 0xD0, 0x03, 0x28, + 0x2E, 0xD0, 0x04, 0x28, 0x00, 0xD0, 0x01, 0x24, 0x6B, 0x46, 0x2A, 0x46, + 0x31, 0x46, 0x38, 0x46, + 0xFC, 0xF7, 0xAE, 0xF9, 0x40, 0xEA, 0x04, 0x05, 0x02, 0x20, 0xEF, 0xF7, + 0xD5, 0xFE, 0x9D, 0xF8, + 0x00, 0x00, 0x98, 0xB1, 0xEF, 0xF7, 0x94, 0xFC, 0x17, 0x48, 0x18, 0x4A, + 0x01, 0x68, 0x12, 0x68, + 0x11, 0x43, 0x01, 0x60, 0xEF, 0xF7, 0x8A, 0xFC, 0x15, 0x48, 0x01, 0x78, + 0x05, 0x20, 0x01, 0xF0, + 0xCA, 0xFF, 0x4F, 0xF4, 0x80, 0x71, 0x00, 0x20, 0xEF, 0xF7, 0xC3, 0xFD, + 0x28, 0x46, 0xF8, 0xBD, + 0xFD, 0xF7, 0xA4, 0xFE, 0xFB, 0xF7, 0xD9, 0xFA, 0xD6, 0xE7, 0xFD, 0xF7, + 0x5E, 0xFC, 0x01, 0xE0, + 0xF7, 0xF7, 0x47, 0xFB, 0xFB, 0xF7, 0xFD, 0xFA, 0xCE, 0xE7, 0x00, 0x00, + 0x1C, 0x07, 0x10, 0x00, + 0x74, 0x06, 0x10, 0x00, 0x79, 0x07, 0x10, 0x00, 0x74, 0x07, 0x10, 0x00, + 0x04, 0x07, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, 0x54, 0x07, 0x10, 0x00, + 0x30, 0x06, 0x10, 0x00, + 0x2C, 0x06, 0x10, 0x00, 0x06, 0x28, 0x08, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, + 0x07, 0x03, 0x03, 0x03, + 0x05, 0x05, 0x01, 0x20, 0x70, 0x47, 0x02, 0x20, 0x70, 0x47, 0x00, 0x20, + 0x70, 0x47, 0x10, 0xB5, + 0x04, 0x46, 0x08, 0x46, 0xFF, 0xF7, 0xEE, 0xFF, 0xA8, 0x4A, 0x01, 0x21, + 0x81, 0x40, 0x12, 0x68, + 0x11, 0x42, 0x09, 0xD1, 0x02, 0x28, 0x07, 0xDC, 0xA5, 0x49, 0x51, 0xF8, + 0x20, 0x10, 0x21, 0x60, + 0xA4, 0x49, 0x41, 0xF8, 0x20, 0x40, 0x10, 0xBD, 0x00, 0x20, 0x20, 0x60, + 0x21, 0x46, 0xBD, 0xE8, + 0x10, 0x40, 0x48, 0x20, 0x01, 0xF0, 0x2D, 0xBD, 0x70, 0xB5, 0x04, 0x46, + 0x08, 0x46, 0xFF, 0xF7, + 0xD1, 0xFF, 0x00, 0x25, 0x88, 0xB1, 0x02, 0x28, 0x0F, 0xDC, 0x99, 0x4A, + 0x21, 0x68, 0x52, 0xF8, + 0x20, 0x20, 0x91, 0x42, 0x09, 0xD1, 0x95, 0x49, 0x01, 0x22, 0x82, 0x40, + 0x0B, 0x68, 0x93, 0x43, + 0x0B, 0x60, 0x94, 0x49, 0x41, 0xF8, 0x20, 0x50, 0x03, 0xE0, 0x21, 0x46, + 0x49, 0x20, 0x01, 0xF0, + 0x10, 0xFD, 0x25, 0x60, 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x01, 0x24, + 0x8B, 0x4E, 0x8D, 0x4F, + 0x4F, 0xF0, 0x00, 0x08, 0x25, 0x46, 0x00, 0xBF, 0x31, 0x68, 0x05, 0xFA, + 0x04, 0xF0, 0x08, 0x42, + 0x08, 0xD0, 0x81, 0x43, 0x31, 0x60, 0x57, 0xF8, 0x24, 0x10, 0x4A, 0x20, + 0x01, 0xF0, 0xF9, 0xFC, + 0x47, 0xF8, 0x24, 0x80, 0x64, 0x1C, 0x02, 0x2C, 0xEE, 0xDD, 0xBD, 0xE8, + 0xF0, 0x81, 0x2D, 0xE9, + 0xF0, 0x41, 0x80, 0x4D, 0x0A, 0x46, 0x00, 0x27, 0x0C, 0x35, 0x7C, 0x4B, + 0x7E, 0x4C, 0x05, 0xF1, + 0x14, 0x06, 0x03, 0xF1, 0x08, 0x01, 0x07, 0x60, 0x01, 0x2A, 0x63, 0xD0, + 0x02, 0x2A, 0x39, 0xD0, + 0x03, 0x2A, 0x6A, 0xD1, 0x5F, 0xF0, 0x00, 0x02, 0x11, 0xF8, 0x02, 0xC0, + 0xBC, 0xF1, 0x00, 0x0F, + 0x10, 0xD1, 0x01, 0xEB, 0x02, 0x0C, 0x9C, 0xF8, 0x01, 0xE0, 0xBE, 0xF1, + 0x00, 0x0F, 0x09, 0xD1, + 0x9C, 0xF8, 0x02, 0xE0, 0xBE, 0xF1, 0x00, 0x0F, 0x04, 0xD1, 0x9C, 0xF8, + 0x03, 0xE0, 0xBE, 0xF1, + 0x00, 0x0F, 0x0B, 0xD0, 0x02, 0xF1, 0x04, 0x0C, 0x52, 0x1C, 0xBC, 0xF1, + 0x05, 0x0F, 0xE3, 0xDB, + 0x59, 0x68, 0x04, 0x29, 0x47, 0xD3, 0x01, 0x46, 0x4C, 0x20, 0x48, 0xE0, + 0x73, 0x27, 0x57, 0x43, + 0x04, 0xEB, 0xC7, 0x04, 0x04, 0x60, 0x45, 0xF8, 0x22, 0x40, 0x46, 0xF8, + 0x22, 0x00, 0x03, 0x20, + 0x88, 0x54, 0x11, 0x44, 0x48, 0x70, 0x8C, 0xF8, 0x02, 0x00, 0x8C, 0xF8, + 0x03, 0x00, 0x58, 0x68, + 0x00, 0x1F, 0x45, 0xE0, 0x5F, 0xF0, 0x00, 0x02, 0x11, 0xF8, 0x02, 0xC0, + 0xBC, 0xF1, 0x00, 0x0F, + 0x06, 0xD1, 0x01, 0xEB, 0x02, 0x0C, 0x9C, 0xF8, 0x01, 0xC0, 0xBC, 0xF1, + 0x00, 0x0F, 0x09, 0xD0, + 0x02, 0xF1, 0x02, 0x0C, 0x52, 0x1C, 0xBC, 0xF1, 0x05, 0x0F, 0xED, 0xDB, + 0x59, 0x68, 0x02, 0x29, + 0xD1, 0xD2, 0x18, 0xE0, 0x73, 0x27, 0x57, 0x43, 0x04, 0xEB, 0xC7, 0x04, + 0x04, 0x60, 0x45, 0xF8, + 0x22, 0x40, 0x46, 0xF8, 0x22, 0x00, 0x02, 0x20, 0x88, 0x54, 0x11, 0x44, + 0x48, 0x70, 0x58, 0x68, + 0x80, 0x1E, 0x1D, 0xE0, 0x5F, 0xF0, 0x04, 0x02, 0x11, 0xF8, 0x02, 0xC0, + 0xBC, 0xF1, 0x00, 0x0F, + 0x09, 0xD0, 0x52, 0x1E, 0xF8, 0xD2, 0x00, 0x2F, 0x13, 0xD1, 0x01, 0x46, + 0x4B, 0x20, 0xBD, 0xE8, + 0xF0, 0x41, 0x01, 0xF0, 0x6E, 0xBC, 0x73, 0x27, 0x57, 0x43, 0x04, 0xEB, + 0xC7, 0x04, 0x04, 0x60, + 0x45, 0xF8, 0x22, 0x40, 0x46, 0xF8, 0x22, 0x00, 0x01, 0x20, 0x88, 0x54, + 0x58, 0x68, 0x40, 0x1E, + 0x58, 0x60, 0x6A, 0xE7, 0xF0, 0xB4, 0x37, 0x4D, 0x34, 0x4C, 0x00, 0x22, + 0x04, 0x23, 0x0C, 0x35, + 0x06, 0x68, 0x08, 0x34, 0x55, 0xF8, 0x23, 0x70, 0xB7, 0x42, 0x14, 0xD1, + 0xE7, 0x5C, 0x8F, 0x42, + 0x11, 0xD1, 0x5A, 0x1C, 0x13, 0xD0, 0x00, 0x22, 0x02, 0x60, 0x45, 0xF8, + 0x23, 0x20, 0x2D, 0x4D, + 0x20, 0x35, 0x01, 0x29, 0x45, 0xF8, 0x23, 0x20, 0xE2, 0x54, 0x11, 0xD0, + 0x02, 0x29, 0x11, 0xD0, + 0x03, 0x29, 0x04, 0xD1, 0x08, 0xE0, 0x5B, 0x1E, 0xE4, 0xD2, 0x00, 0x2A, + 0x08, 0xD1, 0xF0, 0xBC, + 0x01, 0x46, 0x4D, 0x20, 0x01, 0xF0, 0x35, 0xBC, 0xE0, 0x18, 0x42, 0x70, + 0x82, 0x70, 0xC2, 0x70, + 0xF0, 0xBC, 0x70, 0x47, 0xE0, 0x18, 0x42, 0x70, 0xFA, 0xE7, 0x2D, 0xE9, + 0xF0, 0x41, 0x1D, 0x4E, + 0x1A, 0x4F, 0x0C, 0x36, 0x05, 0x24, 0x06, 0xF1, 0x14, 0x05, 0x08, 0x37, + 0x0D, 0xE0, 0x00, 0xBF, + 0x56, 0xF8, 0x24, 0x00, 0x48, 0xB1, 0x55, 0xF8, 0x24, 0x10, 0x4E, 0x20, + 0x01, 0xF0, 0x19, 0xFC, + 0x39, 0x5D, 0x55, 0xF8, 0x24, 0x00, 0xFF, 0xF7, 0xB5, 0xFF, 0x64, 0x1E, + 0xF0, 0xD2, 0x1C, 0xE7, + 0x30, 0xB5, 0x0E, 0x4A, 0x01, 0x20, 0x01, 0x46, 0x0E, 0x4B, 0x10, 0x60, + 0x5F, 0xF0, 0x00, 0x00, + 0x43, 0xF8, 0x21, 0x00, 0x49, 0x1C, 0x02, 0x29, 0xFA, 0xDD, 0x05, 0x21, + 0x09, 0x4C, 0x51, 0x60, + 0x0C, 0x34, 0x06, 0x4A, 0x04, 0x21, 0x08, 0x32, 0x04, 0xF1, 0x14, 0x03, + 0x44, 0xF8, 0x21, 0x00, + 0x50, 0x54, 0x43, 0xF8, 0x21, 0x00, 0x49, 0x1E, 0xF8, 0xD2, 0x30, 0xBD, + 0xB0, 0x06, 0x10, 0x00, + 0x3C, 0x7A, 0x01, 0x00, 0x9C, 0x4E, 0x10, 0x00, 0xD4, 0x56, 0x10, 0x00, + 0x73, 0x49, 0x00, 0x20, + 0x74, 0x4B, 0x08, 0x70, 0x72, 0x49, 0x01, 0x22, 0x88, 0x60, 0xC8, 0x60, + 0x08, 0x70, 0x1A, 0x70, + 0xC1, 0xF8, 0x01, 0x00, 0x70, 0x47, 0xFE, 0xB5, 0x6F, 0x4C, 0x6E, 0x4D, + 0x70, 0x4F, 0x22, 0x68, + 0xB2, 0xF8, 0x7A, 0x14, 0xAD, 0xF8, 0x04, 0x10, 0xB2, 0xF8, 0x7C, 0x14, + 0xAD, 0xF8, 0x06, 0x10, + 0xB2, 0xF8, 0x7E, 0x14, 0xAD, 0xF8, 0x08, 0x10, 0xB2, 0xF8, 0x80, 0x14, + 0xAD, 0xF8, 0x0A, 0x10, + 0x66, 0x49, 0x03, 0x68, 0x0B, 0x60, 0x43, 0x68, 0x4B, 0x60, 0x29, 0x78, + 0x00, 0x91, 0x92, 0xF8, + 0x82, 0x14, 0xB7, 0xF9, 0x00, 0x20, 0x01, 0xF0, 0x0F, 0x03, 0x01, 0x46, + 0x5F, 0x48, 0x08, 0x30, + 0x03, 0xF0, 0x0C, 0xFA, 0x00, 0x26, 0x2E, 0x70, 0x03, 0x20, 0xEF, 0xF7, + 0xDA, 0xFC, 0x5B, 0x49, + 0xB7, 0xF9, 0x00, 0x30, 0x08, 0x31, 0x5B, 0x4A, 0x01, 0xF1, 0x08, 0x00, + 0x03, 0xF0, 0xF1, 0xF9, + 0x03, 0x20, 0xEF, 0xF7, 0xE9, 0xFC, 0x55, 0x48, 0x01, 0xA9, 0x10, 0x30, + 0x00, 0xF0, 0x27, 0xF8, + 0x4E, 0x49, 0x4F, 0x4D, 0xC0, 0xB1, 0x01, 0x26, 0x0E, 0x70, 0x21, 0x68, + 0x91, 0xF8, 0x60, 0x14, + 0x89, 0x07, 0x12, 0xD5, 0x04, 0x46, 0x00, 0x90, 0x04, 0x21, 0x68, 0x46, + 0xF0, 0xF7, 0x23, 0xFA, + 0xC0, 0xB2, 0x01, 0x28, 0x02, 0xD9, 0xA8, 0x68, 0x10, 0xB1, 0x04, 0x46, + 0x20, 0x46, 0x04, 0xE0, + 0x28, 0x78, 0x86, 0x40, 0x34, 0x43, 0xF9, 0xE7, 0x0E, 0x70, 0xA9, 0x68, + 0x00, 0xF0, 0x43, 0xF8, + 0xA9, 0x68, 0x88, 0x42, 0x02, 0xD0, 0xA8, 0x60, 0x01, 0xF0, 0xA4, 0xFD, + 0xFE, 0xBD, 0x2D, 0xE9, + 0xFC, 0x43, 0x04, 0x46, 0x00, 0x20, 0x89, 0x46, 0xDF, 0xF8, 0xEC, 0xC0, + 0x80, 0x46, 0x6E, 0x46, + 0x00, 0x90, 0x03, 0x46, 0x02, 0x46, 0x01, 0x21, 0xCD, 0xF8, 0x04, 0x00, + 0xDC, 0xF8, 0x00, 0x50, + 0x95, 0xF8, 0x61, 0x74, 0x01, 0xFA, 0x02, 0xF5, 0x2F, 0x42, 0x05, 0xD0, + 0x34, 0xF8, 0x13, 0x50, + 0x5B, 0x1C, 0x26, 0xF8, 0x12, 0x50, 0x1B, 0xB2, 0x52, 0x1C, 0x12, 0xB2, + 0x04, 0x2A, 0xED, 0xDB, + 0x2F, 0x4B, 0x34, 0x46, 0x00, 0x22, 0x2A, 0x4E, 0xB3, 0xF9, 0x00, 0x50, + 0x0F, 0xE0, 0x00, 0xBF, + 0x34, 0xF9, 0x12, 0x30, 0x39, 0xF9, 0x12, 0x70, 0xBB, 0x42, 0x06, 0xDD, + 0x01, 0xFA, 0x02, 0xF7, + 0x38, 0x43, 0x43, 0x45, 0x01, 0xDD, 0x98, 0x46, 0x32, 0x70, 0x52, 0x1C, + 0x12, 0xB2, 0xAA, 0x42, + 0xEE, 0xDB, 0xBD, 0xE8, 0xFC, 0x83, 0x2D, 0xE9, 0xF0, 0x43, 0x1D, 0x4F, + 0x89, 0x46, 0x00, 0x22, + 0xF9, 0x68, 0x4F, 0xF0, 0x01, 0x08, 0x80, 0xEA, 0x01, 0x04, 0x1B, 0x49, + 0x7B, 0x1C, 0x0D, 0x68, + 0x1B, 0x49, 0xB1, 0xF9, 0x00, 0x60, 0x1B, 0xE0, 0x08, 0xFA, 0x02, 0xF1, + 0x21, 0x42, 0x0A, 0xD0, + 0x95, 0xF8, 0x83, 0xC4, 0x01, 0x42, 0x02, 0xD0, 0x0C, 0xF0, 0x0F, 0x0C, + 0x01, 0xE0, 0x4F, 0xEA, + 0x1C, 0x1C, 0x03, 0xF8, 0x02, 0xC0, 0x13, 0xF9, 0x02, 0xC0, 0xBC, 0xF1, + 0x00, 0x0F, 0x0D, 0xD0, + 0x03, 0xDD, 0xAC, 0xF1, 0x01, 0x0C, 0x03, 0xF8, 0x02, 0xC0, 0x02, 0xF1, + 0x01, 0x02, 0x12, 0xB2, + 0xB2, 0x42, 0xE1, 0xDB, 0xF8, 0x60, 0x48, 0x46, 0xBD, 0xE8, 0xF0, 0x83, + 0x01, 0x42, 0x02, 0xD0, + 0x41, 0xEA, 0x09, 0x09, 0xF1, 0xE7, 0x29, 0xEA, 0x01, 0x09, 0xEE, 0xE7, + 0x2C, 0x07, 0x10, 0x00, + 0xC0, 0x06, 0x10, 0x00, 0x7B, 0x07, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x9A, 0x1C, 0x01, 0x20, + 0x00, 0x07, 0x10, 0x00, 0xF4, 0x4A, 0x01, 0x20, 0xF0, 0xB5, 0x06, 0x46, + 0xF8, 0x48, 0x00, 0x24, + 0xA7, 0xB0, 0x00, 0x78, 0x0D, 0x46, 0x01, 0x28, 0x00, 0xD1, 0x01, 0x24, + 0x98, 0x21, 0x68, 0x46, + 0x06, 0xF0, 0xC4, 0xF9, 0xF3, 0x4A, 0x00, 0x21, 0x68, 0x46, 0x13, 0x78, + 0x11, 0xE0, 0x00, 0xBF, + 0x01, 0xFB, 0x03, 0xF7, 0x22, 0x46, 0x09, 0xE0, 0x07, 0xEB, 0x02, 0x0E, + 0x50, 0xF8, 0x22, 0xC0, + 0x36, 0xF9, 0x1E, 0xE0, 0xF4, 0x44, 0x40, 0xF8, 0x22, 0xC0, 0x52, 0x1C, + 0x9A, 0x42, 0xF3, 0xDB, + 0x49, 0x1C, 0xA9, 0x42, 0xEC, 0xDB, 0x21, 0x46, 0x07, 0xE0, 0x00, 0xBF, + 0x50, 0xF8, 0x21, 0x20, + 0x92, 0xFB, 0xF5, 0xF2, 0x40, 0xF8, 0x21, 0x20, 0x49, 0x1C, 0x99, 0x42, + 0xF6, 0xDB, 0x00, 0x21, + 0x17, 0xE0, 0x00, 0x27, 0x3A, 0x46, 0x0C, 0xE0, 0x02, 0xFB, 0x03, 0x4C, + 0x50, 0xF8, 0x24, 0xE0, + 0x36, 0xF9, 0x1C, 0xC0, 0xBC, 0xEB, 0x0E, 0x0C, 0x01, 0xD5, 0xCC, 0xF1, + 0x00, 0x0C, 0x67, 0x44, + 0x52, 0x1C, 0xAA, 0x42, 0xF0, 0xDB, 0x97, 0xFB, 0xF5, 0xF2, 0x8A, 0x42, + 0x00, 0xDD, 0x11, 0x46, + 0x64, 0x1C, 0x9C, 0x42, 0xE5, 0xDB, 0xB1, 0xF5, 0x80, 0x3F, 0x03, 0xDB, + 0x4F, 0xF6, 0xFF, 0x70, + 0x27, 0xB0, 0xF0, 0xBD, 0x88, 0xB2, 0xFB, 0xE7, 0xF0, 0xB5, 0xCF, 0x49, + 0xCF, 0x4B, 0x09, 0x68, + 0x91, 0xF8, 0xA0, 0x22, 0xD2, 0x07, 0x34, 0xD0, 0xCD, 0x4A, 0x57, 0x78, + 0x4F, 0xB1, 0x91, 0xF8, + 0xAB, 0x42, 0xB1, 0xF8, 0xA8, 0x52, 0x04, 0xF0, 0x0F, 0x02, 0x26, 0x09, + 0xB1, 0xF8, 0xA6, 0x42, + 0x08, 0xE0, 0x91, 0xF8, 0xAA, 0x42, 0xB1, 0xF8, 0xA4, 0x52, 0x04, 0xF0, + 0x0F, 0x02, 0x26, 0x09, + 0xB1, 0xF8, 0xA2, 0x42, 0xDF, 0xF8, 0x0C, 0xC3, 0x9C, 0xF8, 0x00, 0xC0, + 0xBC, 0xF1, 0x03, 0x0F, + 0x06, 0xD1, 0x91, 0xF8, 0xAC, 0x12, 0x0F, 0xB1, 0x0A, 0x09, 0x01, 0xE0, + 0x01, 0xF0, 0x0F, 0x02, + 0xA0, 0x42, 0x01, 0xDC, 0x1A, 0x60, 0xF0, 0xBD, 0xA8, 0x42, 0x01, 0xDB, + 0x1E, 0x60, 0xF0, 0xBD, + 0x00, 0x1B, 0xB1, 0x1A, 0x48, 0x43, 0x29, 0x1B, 0x90, 0xFB, 0xF1, 0xF0, + 0x10, 0x44, 0x18, 0x60, + 0xF0, 0xBD, 0x00, 0x20, 0xFB, 0xE7, 0xB0, 0x48, 0xB1, 0x49, 0x00, 0x68, + 0x0A, 0x78, 0x00, 0xF5, + 0xF9, 0x70, 0x80, 0x5C, 0xC8, 0x70, 0x70, 0x47, 0x2D, 0xE9, 0xF0, 0x0F, + 0x83, 0x46, 0xAA, 0x48, + 0xDF, 0xF8, 0xAC, 0x92, 0xDF, 0xF8, 0xB0, 0xA2, 0x01, 0x68, 0x99, 0xF8, + 0x00, 0x70, 0x00, 0x20, + 0x91, 0xF8, 0x0A, 0x62, 0x91, 0xF8, 0x09, 0x12, 0x3A, 0xF8, 0x17, 0x40, + 0x6F, 0xF0, 0x00, 0x42, + 0x4F, 0xEA, 0x11, 0x18, 0x0B, 0x07, 0x1C, 0xD0, 0x01, 0xF0, 0x0F, 0x05, + 0x9E, 0x4B, 0x00, 0x21, + 0x8C, 0x46, 0x1B, 0x68, 0xB4, 0x42, 0x93, 0xF8, 0x08, 0x32, 0x05, 0xDB, + 0xA6, 0x1B, 0x06, 0xFB, + 0x08, 0xF6, 0x96, 0xFB, 0xF5, 0xF5, 0x2B, 0x44, 0x97, 0x4D, 0x99, 0xF8, + 0x01, 0x60, 0x2D, 0x68, + 0x01, 0x2E, 0x95, 0xF8, 0xF1, 0x51, 0x06, 0xD0, 0x02, 0x2E, 0x07, 0xD0, + 0x05, 0xF0, 0x03, 0x06, + 0x13, 0xE0, 0x01, 0x25, 0xE2, 0xE7, 0xC5, 0xF3, 0x81, 0x06, 0x0E, 0xE0, + 0xC5, 0xF3, 0x01, 0x16, + 0x0B, 0xE0, 0x00, 0xBF, 0x3A, 0xF8, 0x1C, 0x50, 0xAA, 0x42, 0x01, 0xDD, + 0x2A, 0x46, 0x60, 0x46, + 0xA9, 0x42, 0x00, 0xDA, 0x29, 0x46, 0x0C, 0xF1, 0x01, 0x0C, 0xB4, 0x45, + 0xF2, 0xDD, 0xAB, 0xF8, + 0x00, 0x10, 0xA1, 0x1A, 0x99, 0x42, 0x01, 0xDC, 0xB7, 0x42, 0x04, 0xDD, + 0x89, 0xF8, 0x00, 0x00, + 0xBD, 0xE8, 0xF0, 0x0F, 0x9F, 0xE7, 0xBD, 0xE8, 0xF0, 0x0F, 0x70, 0x47, + 0x83, 0x49, 0x10, 0xB5, + 0x0B, 0x78, 0x7D, 0x49, 0x00, 0x22, 0x01, 0x2B, 0x09, 0x68, 0x02, 0xD1, + 0x80, 0x4B, 0x1B, 0x78, + 0x4B, 0xB1, 0xB1, 0xF8, 0xFC, 0x31, 0x83, 0x42, 0x18, 0xD2, 0x91, 0xF8, + 0xF0, 0x31, 0x1B, 0x07, + 0x14, 0xD5, 0x03, 0x22, 0x25, 0xE0, 0xB1, 0xF8, 0x02, 0x32, 0x83, 0x42, + 0x03, 0xD2, 0x91, 0xF8, + 0xF0, 0x31, 0x1B, 0x07, 0xF5, 0xD4, 0xB1, 0xF8, 0x00, 0x32, 0x83, 0x42, + 0x03, 0xD2, 0x91, 0xF8, + 0xF0, 0x31, 0x5B, 0x07, 0x0A, 0xD4, 0xB1, 0xF8, 0xFE, 0x31, 0x0B, 0xE0, + 0xB1, 0xF8, 0xFA, 0x31, + 0x83, 0x42, 0x05, 0xD2, 0x91, 0xF8, 0xF0, 0x31, 0x5B, 0x07, 0x01, 0xD5, + 0x02, 0x22, 0x08, 0xE0, + 0xB1, 0xF8, 0xF8, 0x31, 0x83, 0x42, 0x04, 0xD2, 0x91, 0xF8, 0xF0, 0x01, + 0x80, 0x07, 0x00, 0xD5, + 0x01, 0x22, 0x65, 0x48, 0x62, 0x4C, 0x14, 0x38, 0x03, 0x78, 0x9A, 0x42, + 0x11, 0xD1, 0x61, 0x78, + 0x99, 0x42, 0x1A, 0xD0, 0x63, 0x4A, 0x12, 0x78, 0x13, 0x43, 0x07, 0xD0, + 0x81, 0x68, 0x49, 0x1E, + 0x81, 0x60, 0x00, 0x29, 0x11, 0xDC, 0x00, 0x78, 0x60, 0x70, 0x0E, 0xE0, + 0x01, 0x70, 0x81, 0x68, + 0xF7, 0xE7, 0x8A, 0xB1, 0x02, 0x2A, 0x01, 0xD1, 0x01, 0x2B, 0x0D, 0xD0, + 0x91, 0xF8, 0xF6, 0x11, + 0x81, 0x60, 0x02, 0x70, 0x00, 0x29, 0x00, 0xDC, 0x62, 0x70, 0x57, 0x48, + 0x62, 0x78, 0x41, 0x7B, + 0x62, 0xF3, 0x03, 0x01, 0x41, 0x73, 0x10, 0xBD, 0x91, 0xF8, 0xF7, 0x11, + 0xF0, 0xE7, 0x4A, 0x4A, + 0x12, 0x68, 0x92, 0xF8, 0xF0, 0x21, 0xD2, 0x06, 0x07, 0xD5, 0x42, 0x1A, + 0x00, 0x2A, 0x04, 0xDC, + 0xC1, 0xEB, 0xC1, 0x11, 0x08, 0x44, 0xC0, 0xF3, 0xCF, 0x10, 0x70, 0x47, + 0x44, 0x49, 0x00, 0x20, + 0x41, 0x4A, 0x48, 0x70, 0x44, 0x49, 0x14, 0x39, 0x48, 0x60, 0x88, 0x60, + 0x08, 0x70, 0x12, 0x68, + 0x92, 0xF8, 0xA0, 0x32, 0xDB, 0x07, 0x03, 0xD0, 0x92, 0xF8, 0xAB, 0x22, + 0x12, 0x09, 0x00, 0xE0, + 0x00, 0x22, 0x3A, 0x4B, 0x1A, 0x60, 0xC8, 0x60, 0x08, 0x61, 0x48, 0x61, + 0x88, 0x61, 0x70, 0x47, + 0x2D, 0xE9, 0xF8, 0x4F, 0x00, 0x21, 0xAD, 0xF8, 0x00, 0x10, 0x32, 0x49, + 0xDF, 0xF8, 0xD8, 0x90, + 0xDF, 0xF8, 0xD4, 0x80, 0x0D, 0x78, 0x4F, 0xF0, 0x10, 0x0B, 0x2F, 0x01, + 0x06, 0x46, 0x00, 0x24, + 0xA9, 0xF1, 0x08, 0x09, 0xA8, 0xF1, 0x14, 0x0A, 0x10, 0xE0, 0x2A, 0x46, + 0x59, 0x46, 0x30, 0x46, + 0xFF, 0xF7, 0x5A, 0xFE, 0x29, 0xF8, 0x14, 0x00, 0x43, 0x46, 0x38, 0xF8, + 0x14, 0x10, 0xFF, 0xF7, + 0xB6, 0xFF, 0x23, 0xF8, 0x14, 0x00, 0x06, 0xEB, 0x47, 0x06, 0x64, 0x1C, + 0x9A, 0xF8, 0x01, 0x00, + 0x84, 0x42, 0xEA, 0xDD, 0x68, 0x46, 0xFF, 0xF7, 0xE7, 0xFE, 0x1F, 0x48, + 0x20, 0x4D, 0x00, 0x68, + 0x90, 0xF8, 0xF0, 0x01, 0x40, 0x06, 0x02, 0xD5, 0xBD, 0xF8, 0x00, 0x40, + 0x02, 0xE0, 0x29, 0x78, + 0x38, 0xF8, 0x11, 0x40, 0x21, 0x48, 0x04, 0x80, 0x20, 0x46, 0xFF, 0xF7, + 0x2F, 0xFF, 0x20, 0x46, + 0xFF, 0xF7, 0x8A, 0xFE, 0x29, 0x78, 0x39, 0xF8, 0x11, 0x00, 0x1B, 0x49, + 0xA1, 0xF8, 0x1B, 0x00, + 0xBD, 0xE8, 0xF8, 0x8F, 0x2D, 0xE9, 0xFC, 0x5F, 0x0E, 0x49, 0x4F, 0xF0, + 0x00, 0x09, 0x0D, 0x78, + 0x0B, 0x49, 0x09, 0x78, 0x01, 0x29, 0x00, 0xD1, 0x89, 0x46, 0x0F, 0x49, + 0x10, 0x26, 0x14, 0x39, + 0x04, 0x46, 0x4A, 0x68, 0x12, 0x48, 0x92, 0xFB, 0xF6, 0xF3, 0x06, 0xFB, + 0x13, 0x22, 0x6A, 0x43, + 0x4F, 0x78, 0x4F, 0xEA, 0x05, 0x1A, 0x00, 0xEB, 0x42, 0x08, 0x83, 0x46, + 0x7F, 0x1C, 0x3D, 0xE0, + 0xF3, 0x06, 0x10, 0x00, 0xEE, 0x06, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x9C, 0x06, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, 0xEC, 0x06, 0x10, 0x00, 0xE4, 0x06, 0x10, 0x00, + 0xF6, 0x06, 0x10, 0x00, + 0xF7, 0x06, 0x10, 0x00, 0xF5, 0x06, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, + 0x78, 0x06, 0x10, 0x00, + 0xB2, 0x1C, 0x01, 0x20, 0x2A, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xF0, 0x11, + 0x89, 0x06, 0x14, 0xD5, + 0x28, 0x49, 0x49, 0x68, 0x00, 0x29, 0x0E, 0xDD, 0xA5, 0xEB, 0x09, 0x02, + 0xB0, 0xF9, 0x06, 0x12, + 0xCD, 0xE9, 0x00, 0x12, 0xB0, 0xF9, 0x04, 0x32, 0x04, 0xEB, 0x49, 0x00, + 0x0B, 0xEB, 0x49, 0x02, + 0x01, 0x46, 0x02, 0xF0, 0x9D, 0xFE, 0x0B, 0xEB, 0x4A, 0x0B, 0x6A, 0x00, + 0x21, 0x46, 0x40, 0x46, + 0x05, 0xF0, 0x03, 0xFF, 0x04, 0xEB, 0x45, 0x04, 0x08, 0xEB, 0x4A, 0x08, + 0x7F, 0x1E, 0xD9, 0xD2, + 0x18, 0x48, 0x4F, 0xF0, 0xFF, 0x31, 0x01, 0xEB, 0x46, 0x01, 0x42, 0x68, + 0x52, 0x1C, 0x42, 0x60, + 0x91, 0x42, 0x00, 0xDA, 0x46, 0x60, 0x40, 0x68, 0xB0, 0x42, 0x03, 0xDB, + 0xBD, 0xE8, 0xFC, 0x5F, + 0x11, 0x48, 0x45, 0xE7, 0xBD, 0xE8, 0xFC, 0x9F, 0x28, 0xE7, 0x10, 0xB5, + 0x0C, 0x4C, 0x20, 0x68, + 0x90, 0xF8, 0xF1, 0x01, 0xC0, 0xF3, 0x01, 0x12, 0xC0, 0xF3, 0x81, 0x01, + 0x00, 0xF0, 0x03, 0x00, + 0x01, 0xF0, 0x5B, 0xFF, 0x07, 0x49, 0x48, 0x70, 0x20, 0x68, 0x08, 0x49, + 0x90, 0xF8, 0xEC, 0x00, + 0x00, 0xF0, 0x03, 0x00, 0x08, 0x70, 0xFF, 0xF7, 0x36, 0xFE, 0xBD, 0xE8, + 0x10, 0x40, 0x0D, 0xE7, + 0x4C, 0x07, 0x10, 0x00, 0xD0, 0x06, 0x10, 0x00, 0xB2, 0x1C, 0x01, 0x20, + 0x74, 0x07, 0x10, 0x00, + 0x10, 0xB5, 0xBA, 0x48, 0x00, 0x24, 0x84, 0x61, 0x04, 0x62, 0xC4, 0x61, + 0xFF, 0xF7, 0xB9, 0xFA, + 0xFF, 0xF7, 0x6E, 0xFC, 0xB6, 0x48, 0x04, 0x80, 0xBD, 0xE8, 0x10, 0x40, + 0x00, 0xF0, 0x11, 0xB9, + 0x10, 0xB5, 0xB4, 0x48, 0xB1, 0x4C, 0x90, 0xF8, 0x30, 0x10, 0x61, 0x70, + 0x90, 0xF8, 0x31, 0x20, + 0xA2, 0x70, 0x51, 0x43, 0x61, 0x82, 0x90, 0xF8, 0x33, 0x10, 0xE1, 0x70, + 0x10, 0xF8, 0x2C, 0x1F, + 0x21, 0x70, 0x41, 0x78, 0x21, 0x71, 0x81, 0x78, 0x61, 0x71, 0xC1, 0x78, + 0xA1, 0x71, 0x41, 0x7A, + 0xE1, 0x71, 0x80, 0x7A, 0x20, 0x72, 0xA8, 0x48, 0x60, 0x62, 0x00, 0xF2, + 0x3C, 0x60, 0xA0, 0x62, + 0xA0, 0xF6, 0x78, 0x40, 0xE0, 0x62, 0xA5, 0x48, 0x20, 0x63, 0xA5, 0x48, + 0x01, 0x21, 0x00, 0x68, + 0x00, 0xF2, 0x61, 0x40, 0xEF, 0xF7, 0xDF, 0xFE, 0xA0, 0x82, 0x10, 0xBD, + 0x9D, 0x48, 0x10, 0xB5, + 0x9B, 0x49, 0x90, 0xF8, 0x2C, 0x00, 0x99, 0x4A, 0x88, 0x70, 0x08, 0x79, + 0x53, 0x7A, 0x63, 0xF3, + 0x00, 0x00, 0xD3, 0x7A, 0x63, 0xF3, 0xC3, 0x00, 0x93, 0x7A, 0x63, 0xF3, + 0x82, 0x00, 0x13, 0x7B, + 0x63, 0xF3, 0x41, 0x00, 0x97, 0x4B, 0xDB, 0x78, 0x0B, 0x72, 0x93, 0x7B, + 0xCB, 0x71, 0x53, 0x7B, + 0xD4, 0x7B, 0x63, 0xF3, 0x04, 0x10, 0x11, 0xF8, 0x0E, 0x3F, 0x12, 0x7C, + 0x64, 0xF3, 0x03, 0x03, + 0x62, 0xF3, 0x07, 0x13, 0x90, 0x4A, 0x01, 0xF8, 0x0B, 0x39, 0x12, 0x78, + 0x81, 0xF8, 0x25, 0x20, + 0x8E, 0x4A, 0x12, 0x88, 0xCA, 0x84, 0x8E, 0x4A, 0x12, 0x78, 0x62, 0xF3, + 0xC7, 0x10, 0x48, 0x70, + 0x8C, 0x48, 0x00, 0x88, 0x08, 0x85, 0x8C, 0x48, 0x00, 0x88, 0x48, 0x85, + 0x8B, 0x48, 0x02, 0x78, + 0x08, 0x7B, 0x62, 0xF3, 0x03, 0x00, 0x08, 0x73, 0x89, 0x48, 0x02, 0x78, + 0x48, 0x7B, 0x62, 0xF3, + 0x00, 0x00, 0x88, 0x4A, 0x12, 0x78, 0x62, 0xF3, 0x41, 0x00, 0x20, 0xF0, + 0x04, 0x00, 0x48, 0x73, + 0x10, 0xBD, 0x70, 0xB5, 0x0D, 0x46, 0x80, 0xEA, 0x05, 0x04, 0xE0, 0x06, + 0x01, 0xD5, 0xF6, 0xF7, + 0x89, 0xFA, 0xA0, 0x06, 0x01, 0xD5, 0xF4, 0xF7, 0x65, 0xFD, 0x14, 0xF0, + 0x48, 0x0F, 0x05, 0xD0, + 0x6E, 0x48, 0x15, 0xF0, 0x48, 0x01, 0x00, 0xD0, 0x01, 0x21, 0x41, 0x74, + 0x70, 0xBD, 0x70, 0xB5, + 0x79, 0x4D, 0x2C, 0x68, 0x00, 0x2C, 0x0D, 0xD0, 0x68, 0x49, 0xA0, 0xB2, + 0x0A, 0x7A, 0xC9, 0x79, + 0x01, 0xF0, 0x44, 0xF9, 0x28, 0x68, 0xA0, 0x43, 0x28, 0x60, 0x03, 0xD1, + 0xBD, 0xE8, 0x70, 0x40, + 0x01, 0xF0, 0xB7, 0xB9, 0x70, 0xBD, 0xF8, 0xB5, 0x00, 0x26, 0x00, 0xF0, + 0xC1, 0xFF, 0x01, 0x20, + 0xEF, 0xF7, 0xF7, 0xF8, 0x00, 0xF0, 0x8F, 0xF8, 0x5C, 0x4D, 0x5E, 0x4C, + 0x95, 0xF8, 0x20, 0x00, + 0x80, 0x07, 0x02, 0xD5, 0xA0, 0x68, 0xFF, 0xF7, 0xE6, 0xFB, 0x95, 0xF8, + 0x20, 0x00, 0xC0, 0x07, + 0x09, 0xD0, 0xE0, 0x68, 0x00, 0x90, 0xD4, 0xE9, 0x00, 0x01, 0xD4, 0xE9, + 0x04, 0x23, 0xFF, 0xF7, + 0x8A, 0xF9, 0x06, 0x00, 0x0A, 0xD1, 0x28, 0x8C, 0x80, 0x05, 0x07, 0xD5, + 0x94, 0xF8, 0x32, 0x10, + 0xA0, 0x69, 0xF4, 0xF7, 0xF8, 0xFD, 0xE8, 0x69, 0x18, 0xB9, 0x0C, 0xE0, + 0xE8, 0x69, 0x50, 0xB1, + 0x4E, 0xB9, 0x03, 0x20, 0xEF, 0xF7, 0xCD, 0xF8, 0x4A, 0x48, 0xE9, 0x69, + 0xFE, 0xF7, 0x8B, 0xFF, + 0x03, 0x20, 0xEF, 0xF7, 0xE1, 0xF8, 0xFF, 0xF7, 0x51, 0xFF, 0xFF, 0xF7, + 0xB0, 0xFF, 0xFF, 0xF7, + 0x6C, 0xFB, 0xFF, 0xF7, 0x88, 0xFA, 0xBD, 0xE8, 0xF8, 0x40, 0x01, 0x20, + 0xEF, 0xF7, 0xD4, 0xB8, + 0x3E, 0x48, 0x81, 0x7A, 0x01, 0x29, 0x08, 0xD0, 0xC1, 0x7A, 0x01, 0x29, + 0x05, 0xD0, 0x01, 0x7B, + 0x01, 0x29, 0x02, 0xD0, 0x80, 0x7B, 0x00, 0x28, 0x00, 0xD0, 0x01, 0x20, + 0x70, 0x47, 0x08, 0xB5, + 0xFF, 0xF7, 0xF6, 0xFE, 0x6B, 0x46, 0x00, 0x22, 0x03, 0x21, 0x02, 0x20, + 0xEF, 0xF7, 0x0A, 0xF8, + 0x00, 0x98, 0xC0, 0x07, 0x05, 0xD0, 0x01, 0x21, 0x02, 0x20, 0xEE, 0xF7, + 0xE6, 0xFF, 0xFF, 0xF7, + 0x9A, 0xFF, 0x00, 0x98, 0x80, 0x07, 0xED, 0xD5, 0x02, 0x21, 0x08, 0x46, + 0xEE, 0xF7, 0xDD, 0xFF, + 0xE8, 0xE7, 0x2F, 0x48, 0x10, 0xB5, 0x02, 0x68, 0x28, 0x48, 0x00, 0x24, + 0x92, 0xF8, 0x31, 0x10, + 0x41, 0x70, 0x92, 0xF8, 0x30, 0x20, 0x82, 0x70, 0x51, 0x43, 0x41, 0x82, + 0x29, 0x49, 0xC9, 0x78, + 0xC1, 0x70, 0x01, 0x21, 0x01, 0x71, 0x41, 0x71, 0x81, 0x71, 0x01, 0x70, + 0x84, 0x82, 0xC4, 0x71, + 0x04, 0x72, 0xC4, 0x73, 0x04, 0x74, 0xFF, 0xF7, 0x62, 0xF9, 0xFF, 0xF7, + 0x5F, 0xFB, 0xFE, 0xF7, + 0x9D, 0xFE, 0x43, 0xF6, 0x58, 0x61, 0x29, 0x48, 0x05, 0xF0, 0xFE, 0xFD, + 0x28, 0x48, 0x04, 0x80, + 0x28, 0x48, 0x04, 0x80, 0x10, 0xBD, 0x70, 0xB5, 0x14, 0x4E, 0x16, 0x4D, + 0x31, 0x6A, 0x28, 0x6A, + 0x81, 0xEA, 0x00, 0x04, 0x19, 0xB9, 0x10, 0xB1, 0xFF, 0xF7, 0xAA, 0xFE, + 0x11, 0xE0, 0xA0, 0x07, + 0x01, 0xD5, 0xFF, 0xF7, 0x43, 0xFB, 0xE0, 0x07, 0x03, 0xD0, 0xFF, 0xF7, + 0x40, 0xF9, 0xFF, 0xF7, + 0x7B, 0xFE, 0xE0, 0x06, 0x01, 0xD5, 0xFF, 0xF7, 0xED, 0xF8, 0xA0, 0x05, + 0x01, 0xD5, 0xF4, 0xF7, + 0x61, 0xFD, 0xE9, 0x69, 0xB0, 0x69, 0xFF, 0xF7, 0x1C, 0xFF, 0xE8, 0x69, + 0xB0, 0x61, 0x28, 0x6A, + 0x30, 0x62, 0x68, 0x6A, 0xF0, 0x61, 0xBD, 0xE8, 0x70, 0x40, 0x99, 0xE6, + 0xEC, 0x06, 0x10, 0x00, + 0x0A, 0x44, 0x01, 0x20, 0xCC, 0x68, 0x10, 0x00, 0xEE, 0x35, 0x01, 0x20, + 0x42, 0x44, 0x01, 0x20, + 0x4C, 0x07, 0x10, 0x00, 0x74, 0x07, 0x10, 0x00, 0x75, 0x06, 0x10, 0x00, + 0x7A, 0x06, 0x10, 0x00, + 0x7D, 0x07, 0x10, 0x00, 0x7E, 0x07, 0x10, 0x00, 0x80, 0x07, 0x10, 0x00, + 0x66, 0x05, 0x10, 0x00, + 0x64, 0x05, 0x10, 0x00, 0x74, 0x05, 0x10, 0x00, 0x68, 0x07, 0x10, 0x00, + 0x20, 0x4D, 0x01, 0x20, + 0x82, 0x07, 0x10, 0x00, 0x84, 0x07, 0x10, 0x00, 0x0B, 0x4D, 0x00, 0x20, + 0x0B, 0x4C, 0x28, 0x60, + 0x28, 0x68, 0x40, 0x1C, 0x28, 0x60, 0xEE, 0xF7, 0xEB, 0xFD, 0xF0, 0xF7, + 0x70, 0xF9, 0x01, 0x28, + 0x20, 0x68, 0x06, 0xD0, 0x40, 0xF0, 0x04, 0x00, 0x20, 0x60, 0xEE, 0xF7, + 0xDF, 0xFD, 0x30, 0xBF, + 0xEE, 0xE7, 0x20, 0xF0, 0x04, 0x00, 0xF7, 0xE7, 0x30, 0x07, 0x10, 0x00, + 0x10, 0xED, 0x00, 0xE0, + 0x2D, 0xE9, 0xF0, 0x47, 0x1C, 0x4D, 0xDF, 0xF8, 0x74, 0x90, 0xA8, 0x46, + 0x20, 0x21, 0x1A, 0x48, + 0x05, 0xF0, 0x82, 0xFD, 0x18, 0x48, 0x00, 0xF0, 0x53, 0xFB, 0x47, 0x1E, + 0xD9, 0xF8, 0x00, 0x00, + 0x98, 0xF8, 0x00, 0x60, 0x08, 0xF1, 0x01, 0x04, 0x90, 0xF8, 0xA0, 0x00, + 0xC0, 0x07, 0x05, 0xD0, + 0x3A, 0x46, 0x21, 0x46, 0x30, 0x46, 0x00, 0xF0, 0x23, 0xF8, 0x28, 0xB9, + 0x3A, 0x46, 0x21, 0x46, + 0x30, 0x46, 0x00, 0xF0, 0xD3, 0xF8, 0x18, 0xB1, 0x01, 0x20, 0x29, 0x68, + 0x01, 0xF0, 0xF3, 0xF8, + 0x00, 0xF0, 0x50, 0xFB, 0x00, 0x28, 0xD9, 0xD1, 0xBD, 0xE8, 0xF0, 0x87, + 0x38, 0xB5, 0x0C, 0x46, + 0x05, 0x46, 0xEE, 0xF7, 0xE6, 0xFE, 0x69, 0x46, 0x28, 0x46, 0xEE, 0xF7, + 0x1C, 0xFF, 0x00, 0x99, + 0x21, 0x42, 0xF8, 0xD1, 0x38, 0xBD, 0x00, 0x00, 0xD0, 0x4E, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0x70, 0xB5, 0x0D, 0x46, 0x00, 0x24, 0xA0, 0xF1, 0x10, 0x01, 0x03, 0x29, + 0x01, 0xD8, 0x52, 0x48, + 0x05, 0xE0, 0xA0, 0xF1, 0x30, 0x01, 0x0A, 0x29, 0x06, 0xD8, 0x4F, 0x48, + 0x20, 0x30, 0x50, 0xF8, + 0x31, 0x30, 0x00, 0xEB, 0xC1, 0x00, 0x0A, 0xE0, 0x62, 0x28, 0x10, 0xD1, + 0x4A, 0x49, 0xA0, 0xF1, + 0x62, 0x00, 0xA1, 0xF1, 0x08, 0x01, 0x51, 0xF8, 0x30, 0x30, 0x01, 0xEB, + 0xC0, 0x00, 0x4F, 0xF0, + 0x01, 0x04, 0x40, 0x68, 0x90, 0x42, 0x02, 0xD1, 0x11, 0x46, 0x28, 0x46, + 0x98, 0x47, 0x20, 0x46, + 0x70, 0xBD, 0x42, 0x49, 0x43, 0x20, 0x08, 0x60, 0x04, 0x21, 0x01, 0x20, + 0xFF, 0xF7, 0xBE, 0xBF, + 0x3E, 0x49, 0x00, 0x20, 0x08, 0x60, 0x04, 0x21, 0x01, 0x20, 0xFF, 0xF7, + 0xB7, 0xBF, 0xEF, 0xF7, + 0x92, 0xBB, 0x10, 0xB5, 0xEE, 0xF7, 0x5C, 0xFD, 0x39, 0x49, 0x1E, 0x20, + 0x08, 0x60, 0xEE, 0xF7, + 0x55, 0xFD, 0x02, 0x21, 0x05, 0x20, 0x01, 0xF0, 0x96, 0xF8, 0xBD, 0xE8, + 0x10, 0x40, 0x4F, 0xF4, + 0x80, 0x71, 0x00, 0x20, 0xFF, 0xF7, 0xA2, 0xBF, 0x32, 0x49, 0x02, 0x78, + 0x0A, 0x70, 0x42, 0x78, + 0x4A, 0x70, 0x01, 0x78, 0x4B, 0x07, 0x30, 0x49, 0x0A, 0x68, 0x02, 0xD5, + 0x42, 0xF0, 0x04, 0x02, + 0x01, 0xE0, 0x22, 0xF0, 0x04, 0x02, 0x0A, 0x60, 0x02, 0x78, 0x12, 0x07, + 0x0A, 0x68, 0x02, 0xD5, + 0x42, 0xF0, 0x02, 0x02, 0x01, 0xE0, 0x22, 0xF0, 0x02, 0x02, 0x0A, 0x60, + 0x02, 0x78, 0xD2, 0x06, + 0x0A, 0x68, 0x02, 0xD5, 0x42, 0xF0, 0x01, 0x02, 0x01, 0xE0, 0x22, 0xF0, + 0x01, 0x02, 0x0A, 0x60, + 0x00, 0x78, 0x40, 0x06, 0x02, 0xD5, 0x42, 0xF0, 0x10, 0x00, 0x01, 0xE0, + 0x22, 0xF0, 0x10, 0x00, + 0x08, 0x60, 0x08, 0x21, 0x01, 0x20, 0xFF, 0xF7, 0x71, 0xBF, 0x00, 0x78, + 0x28, 0xB1, 0x01, 0x28, + 0x05, 0xD1, 0x10, 0x21, 0x01, 0x20, 0xFF, 0xF7, 0x69, 0xBF, 0x04, 0x21, + 0xFA, 0xE7, 0x70, 0x47, + 0x02, 0x78, 0x15, 0x48, 0x01, 0x68, 0x22, 0xB1, 0x01, 0x2A, 0x05, 0xD0, + 0x02, 0x2A, 0x08, 0xD1, + 0x0B, 0xE0, 0x21, 0xF0, 0x08, 0x01, 0x01, 0xE0, 0x41, 0xF0, 0x08, 0x01, + 0x21, 0xF0, 0x40, 0x01, + 0x01, 0x60, 0x08, 0x21, 0x01, 0x20, 0xFF, 0xF7, 0x51, 0xBF, 0x21, 0xF0, + 0x08, 0x01, 0x41, 0xF0, + 0x40, 0x01, 0xF5, 0xE7, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47, 0x70, 0x47, + 0x70, 0x47, 0x70, 0x47, + 0x70, 0x47, 0x70, 0x47, 0x00, 0xF0, 0x21, 0xBC, 0x50, 0x7A, 0x01, 0x00, + 0x6C, 0x07, 0x10, 0x00, + 0x54, 0x07, 0x10, 0x00, 0xF0, 0x4F, 0x10, 0x00, 0x70, 0x07, 0x10, 0x00, + 0x0B, 0x46, 0x10, 0xB5, + 0x00, 0x21, 0xA0, 0x38, 0x09, 0x28, 0x06, 0xD8, 0xF7, 0x49, 0x51, 0xF8, + 0x20, 0x40, 0x11, 0x46, + 0x18, 0x46, 0xA0, 0x47, 0x01, 0x46, 0x08, 0x46, 0x10, 0xBD, 0x00, 0x20, + 0x70, 0x47, 0x70, 0xB5, + 0x00, 0x23, 0x00, 0x29, 0x11, 0xDD, 0x02, 0x78, 0x49, 0x1E, 0x03, 0x2A, + 0x0D, 0xD2, 0xEE, 0x4D, + 0x40, 0x1C, 0x28, 0x35, 0x55, 0xF8, 0x32, 0x40, 0x05, 0xEB, 0xC2, 0x02, + 0x52, 0x68, 0x00, 0x2A, + 0x03, 0xDB, 0x91, 0x42, 0x01, 0xD1, 0xA0, 0x47, 0x03, 0x46, 0x18, 0x46, + 0x70, 0xBD, 0x10, 0xB5, + 0x00, 0x78, 0x00, 0x21, 0xC2, 0x07, 0x00, 0xD0, 0x01, 0x21, 0x82, 0x07, + 0x01, 0xD5, 0x41, 0xF0, + 0x02, 0x01, 0xC0, 0x06, 0x01, 0xD5, 0x41, 0xF0, 0x40, 0x01, 0xE0, 0x48, + 0x02, 0x68, 0x8A, 0x42, + 0x04, 0xD0, 0x01, 0x60, 0x04, 0x21, 0x01, 0x20, 0xFF, 0xF7, 0xF8, 0xFE, + 0x01, 0x20, 0x10, 0xBD, + 0x00, 0x20, 0x70, 0x47, 0x70, 0xB5, 0x00, 0x23, 0x00, 0x29, 0x0F, 0xDD, + 0x02, 0x78, 0x49, 0x1E, + 0x05, 0x2A, 0x0B, 0xD2, 0xD4, 0x4D, 0x40, 0x1C, 0x40, 0x35, 0x55, 0xF8, + 0x32, 0x40, 0x05, 0xEB, + 0xC2, 0x02, 0x52, 0x68, 0x91, 0x42, 0x01, 0xD1, 0xA0, 0x47, 0x03, 0x46, + 0x18, 0x46, 0x70, 0xBD, + 0x10, 0xB5, 0x00, 0x78, 0xC2, 0x07, 0xCE, 0x48, 0x01, 0x68, 0x02, 0xD0, + 0x41, 0xF0, 0x02, 0x01, + 0x01, 0xE0, 0x21, 0xF0, 0x02, 0x01, 0x01, 0x60, 0x08, 0x21, 0x01, 0x20, + 0xFF, 0xF7, 0xCE, 0xFE, + 0x01, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x78, 0xC2, 0x07, 0xC5, 0x48, + 0x01, 0x68, 0x02, 0xD0, + 0x41, 0xF0, 0x04, 0x01, 0x01, 0xE0, 0x21, 0xF0, 0x04, 0x01, 0x01, 0x60, + 0x08, 0x21, 0x01, 0x20, + 0xFF, 0xF7, 0xBC, 0xFE, 0x01, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x01, 0x78, + 0xCB, 0x07, 0xBC, 0x49, + 0x0A, 0x68, 0x02, 0xD0, 0x42, 0xF0, 0x08, 0x02, 0x01, 0xE0, 0x22, 0xF0, + 0x08, 0x02, 0x0A, 0x60, + 0x00, 0x78, 0x80, 0x07, 0x02, 0xD5, 0x42, 0xF0, 0x40, 0x00, 0x01, 0xE0, + 0x22, 0xF0, 0x40, 0x00, + 0x08, 0x60, 0x08, 0x21, 0x01, 0x20, 0xFF, 0xF7, 0xA1, 0xFE, 0x01, 0x20, + 0x10, 0xBD, 0x00, 0x20, + 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x70, 0xB5, 0x00, 0x23, 0x00, 0x29, + 0x0F, 0xDD, 0x02, 0x78, + 0x49, 0x1E, 0x0A, 0x2A, 0x0B, 0xD2, 0xA8, 0x4D, 0x40, 0x1C, 0x68, 0x35, + 0x55, 0xF8, 0x32, 0x40, + 0x05, 0xEB, 0xC2, 0x02, 0x52, 0x68, 0x91, 0x42, 0x01, 0xD1, 0xA0, 0x47, + 0x03, 0x46, 0x18, 0x46, + 0x70, 0xBD, 0x01, 0x46, 0x00, 0x20, 0x09, 0x78, 0x04, 0x29, 0x06, 0xD2, + 0x9E, 0x48, 0xB8, 0x30, + 0x50, 0xF8, 0x21, 0x20, 0x00, 0x21, 0x08, 0x46, 0x10, 0x47, 0x70, 0x47, + 0x10, 0xB5, 0xEF, 0xF7, + 0x52, 0xFA, 0x01, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0xF0, 0x4F, 0xFB, + 0x01, 0x20, 0x10, 0xBD, + 0x10, 0xB5, 0x4F, 0xF4, 0x00, 0x61, 0x00, 0x20, 0xFF, 0xF7, 0x68, 0xFE, + 0x01, 0x20, 0x10, 0xBD, + 0x10, 0xB5, 0x4F, 0xF4, 0x80, 0x51, 0x00, 0x20, 0xFF, 0xF7, 0x60, 0xFE, + 0x01, 0x20, 0x10, 0xBD, + 0x10, 0xB5, 0x00, 0x78, 0xC0, 0x07, 0x02, 0xD0, 0x00, 0xF0, 0xD8, 0xFA, + 0x01, 0xE0, 0x00, 0xF0, + 0xCC, 0xFA, 0x01, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x88, 0x00, 0x24, + 0xC1, 0x07, 0x00, 0xD0, + 0x02, 0x24, 0x81, 0x07, 0x01, 0xD5, 0x44, 0xF0, 0x04, 0x04, 0x41, 0x07, + 0x01, 0xD5, 0x44, 0xF0, + 0x08, 0x04, 0xC1, 0x06, 0x01, 0xD5, 0x44, 0xF0, 0x10, 0x04, 0x00, 0x06, + 0x01, 0xD5, 0x44, 0xF0, + 0x80, 0x04, 0x94, 0xB1, 0xEE, 0xF7, 0xE4, 0xFB, 0x7E, 0x48, 0x01, 0x68, + 0x21, 0x43, 0x01, 0x60, + 0xEE, 0xF7, 0xDC, 0xFB, 0x02, 0x21, 0x05, 0x20, 0x00, 0xF0, 0x1D, 0xFF, + 0x4F, 0xF4, 0x80, 0x71, + 0x00, 0x20, 0xFF, 0xF7, 0x2B, 0xFE, 0x01, 0x20, 0x10, 0xBD, 0x00, 0x20, + 0x10, 0xBD, 0x10, 0xB5, + 0x00, 0x88, 0x00, 0x24, 0xC1, 0x07, 0x00, 0xD0, 0x01, 0x24, 0x81, 0x07, + 0x01, 0xD5, 0x44, 0xF0, + 0x02, 0x04, 0x41, 0x07, 0x01, 0xD5, 0x44, 0xF0, 0x04, 0x04, 0x01, 0x07, + 0x01, 0xD5, 0x44, 0xF0, + 0x08, 0x04, 0xC1, 0x05, 0x01, 0xD5, 0x44, 0xF4, 0x00, 0x74, 0x81, 0x05, + 0x01, 0xD5, 0x44, 0xF4, + 0x80, 0x64, 0xC1, 0x06, 0x01, 0xD5, 0x44, 0xF0, 0x10, 0x04, 0x00, 0x06, + 0x01, 0xD5, 0x44, 0xF0, + 0x80, 0x04, 0x6C, 0xB1, 0xEE, 0xF7, 0xAC, 0xFB, 0x63, 0x48, 0x01, 0x68, + 0x21, 0x43, 0x01, 0x60, + 0xEE, 0xF7, 0xA4, 0xFB, 0x02, 0x21, 0x00, 0x20, 0xFF, 0xF7, 0xF8, 0xFD, + 0x01, 0x20, 0x10, 0xBD, + 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x88, 0x00, 0x24, 0xC1, 0x07, + 0x00, 0xD0, 0x01, 0x24, + 0x81, 0x07, 0x01, 0xD5, 0x44, 0xF0, 0x02, 0x04, 0x41, 0x07, 0x01, 0xD5, + 0x44, 0xF0, 0x04, 0x04, + 0x01, 0x07, 0x01, 0xD5, 0x44, 0xF0, 0x08, 0x04, 0xC0, 0x06, 0x01, 0xD5, + 0x44, 0xF0, 0x10, 0x04, + 0x74, 0xB1, 0xEE, 0xF7, 0x85, 0xFB, 0x51, 0x48, 0x01, 0x68, 0x21, 0x43, + 0x01, 0x60, 0xEE, 0xF7, + 0x7D, 0xFB, 0x4F, 0xF4, 0x00, 0x11, 0x00, 0x20, 0xFF, 0xF7, 0xD0, 0xFD, + 0x01, 0x20, 0x10, 0xBD, + 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x88, 0x00, 0x24, 0xC1, 0x07, + 0x00, 0xD0, 0x01, 0x24, + 0x81, 0x07, 0x01, 0xD5, 0x44, 0xF0, 0x02, 0x04, 0x41, 0x07, 0x01, 0xD5, + 0x44, 0xF0, 0x04, 0x04, + 0x01, 0x07, 0x01, 0xD5, 0x44, 0xF0, 0x08, 0x04, 0xC1, 0x06, 0x01, 0xD5, + 0x44, 0xF0, 0x10, 0x04, + 0x81, 0x06, 0x01, 0xD5, 0x44, 0xF0, 0x20, 0x04, 0x41, 0x06, 0x01, 0xD5, + 0x44, 0xF0, 0x40, 0x04, + 0x01, 0x06, 0x01, 0xD5, 0x44, 0xF0, 0x80, 0x04, 0xC1, 0x05, 0x01, 0xD5, + 0x44, 0xF4, 0x80, 0x74, + 0x81, 0x05, 0x01, 0xD5, 0x44, 0xF4, 0x00, 0x74, 0x40, 0x05, 0x01, 0xD5, + 0x44, 0xF4, 0x80, 0x64, + 0x6C, 0xB1, 0xEE, 0xF7, 0x45, 0xFB, 0x32, 0x48, 0x01, 0x68, 0x21, 0x43, + 0x01, 0x60, 0xEE, 0xF7, + 0x3D, 0xFB, 0x80, 0x21, 0x00, 0x20, 0xFF, 0xF7, 0x91, 0xFD, 0x01, 0x20, + 0x10, 0xBD, 0x00, 0x20, + 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x78, 0x00, 0x24, 0xC1, 0x07, 0x00, 0xD0, + 0x01, 0x24, 0x81, 0x07, + 0x01, 0xD5, 0x44, 0xF0, 0x02, 0x04, 0x40, 0x07, 0x01, 0xD5, 0x44, 0xF0, + 0x04, 0x04, 0x74, 0xB1, + 0xEE, 0xF7, 0x26, 0xFB, 0x23, 0x48, 0x01, 0x68, 0x21, 0x43, 0x01, 0x60, + 0xEE, 0xF7, 0x1E, 0xFB, + 0x4F, 0xF4, 0x80, 0x61, 0x00, 0x20, 0xFF, 0xF7, 0x71, 0xFD, 0x01, 0x20, + 0x10, 0xBD, 0x00, 0x20, + 0x10, 0xBD, 0x10, 0xB5, 0x00, 0x78, 0x00, 0x24, 0x31, 0x28, 0x39, 0xD0, + 0x10, 0xDC, 0x12, 0x28, + 0x32, 0xD0, 0x06, 0xDC, 0x01, 0x28, 0x1C, 0xD0, 0x10, 0x28, 0x2D, 0xD0, + 0x11, 0x28, 0x31, 0xD1, + 0x2A, 0xE0, 0x13, 0x28, 0x28, 0xD0, 0x14, 0x28, 0x26, 0xD0, 0x30, 0x28, + 0x2A, 0xD1, 0x27, 0xE0, + 0x51, 0x28, 0x29, 0xD0, 0x06, 0xDC, 0x32, 0x28, 0x22, 0xD0, 0x33, 0x28, + 0x20, 0xD0, 0x50, 0x28, + 0x20, 0xD1, 0x21, 0xE0, 0x52, 0x28, 0x1F, 0xD0, 0x53, 0x28, 0x1D, 0xD0, + 0x54, 0x28, 0x19, 0xD1, + 0x1A, 0xE0, 0x00, 0xF0, 0x5B, 0xFC, 0x11, 0xE0, 0xC8, 0x7A, 0x01, 0x00, + 0x6C, 0x07, 0x10, 0x00, + 0x70, 0x07, 0x10, 0x00, 0x54, 0x07, 0x10, 0x00, 0x58, 0x07, 0x10, 0x00, + 0x5C, 0x07, 0x10, 0x00, + 0x64, 0x07, 0x10, 0x00, 0x60, 0x07, 0x10, 0x00, 0x00, 0xF0, 0xDC, 0xFC, + 0x01, 0x24, 0x01, 0xE0, + 0x00, 0xF0, 0xF8, 0xFC, 0x20, 0x46, 0x10, 0xBD, 0x00, 0xF0, 0xE2, 0xFC, + 0xF6, 0xE7, 0x00, 0x00, + 0x08, 0xB5, 0x00, 0xF0, 0x3B, 0xFC, 0x00, 0xF0, 0xE3, 0xFD, 0x17, 0x4C, + 0x6B, 0x46, 0x00, 0x22, + 0x19, 0x21, 0x03, 0x20, 0xEE, 0xF7, 0x4E, 0xFC, 0x00, 0x98, 0xC0, 0x07, + 0x05, 0xD0, 0x01, 0x21, + 0x03, 0x20, 0xEE, 0xF7, 0x2A, 0xFC, 0xFF, 0xF7, 0xE3, 0xFC, 0x00, 0x98, + 0x00, 0x07, 0x0B, 0xD5, + 0x08, 0x21, 0x03, 0x20, 0xEE, 0xF7, 0x21, 0xFC, 0x20, 0x68, 0x08, 0x21, + 0x40, 0xF0, 0x08, 0x00, + 0x20, 0x60, 0x01, 0x20, 0xFF, 0xF7, 0x02, 0xFD, 0x00, 0x98, 0xC0, 0x06, + 0xDE, 0xD5, 0x10, 0x21, + 0x03, 0x20, 0xEE, 0xF7, 0x12, 0xFC, 0x20, 0x68, 0x08, 0x21, 0x20, 0xF0, + 0x08, 0x00, 0x20, 0x60, + 0x01, 0x20, 0xFF, 0xF7, 0xF3, 0xFC, 0xD1, 0xE7, 0x70, 0x07, 0x10, 0x00, + 0x1F, 0x48, 0x00, 0x21, + 0x01, 0x70, 0x41, 0x70, 0x81, 0x70, 0x70, 0x47, 0x10, 0xB5, 0x1C, 0x4C, + 0x03, 0x46, 0xA0, 0x78, + 0x10, 0x28, 0x14, 0xD2, 0x0F, 0x29, 0x00, 0xD9, 0x0F, 0x21, 0x19, 0x48, + 0x22, 0x78, 0x00, 0xEB, + 0x02, 0x10, 0x0A, 0x46, 0x00, 0xF8, 0x01, 0x1B, 0x19, 0x46, 0x05, 0xF0, + 0xB6, 0xF9, 0x20, 0x78, + 0x40, 0x1C, 0x00, 0xF0, 0x0F, 0x00, 0x20, 0x70, 0xA0, 0x78, 0x40, 0x1C, + 0xA0, 0x70, 0x10, 0xBD, + 0x70, 0xB5, 0x0E, 0x4C, 0x00, 0x25, 0xA1, 0x78, 0x91, 0xB1, 0x0D, 0x49, + 0x62, 0x78, 0x01, 0xEB, + 0x02, 0x11, 0x11, 0xF8, 0x01, 0x5B, 0x2A, 0x46, 0x05, 0xF0, 0x9F, 0xF9, + 0x60, 0x78, 0x40, 0x1C, + 0x00, 0xF0, 0x0F, 0x00, 0x60, 0x70, 0x72, 0xB6, 0xA0, 0x78, 0x40, 0x1E, + 0xA0, 0x70, 0x62, 0xB6, + 0x28, 0x46, 0x70, 0xBD, 0x01, 0x48, 0x80, 0x78, 0x70, 0x47, 0x00, 0x00, + 0x34, 0x07, 0x10, 0x00, + 0xF0, 0x4E, 0x10, 0x00, 0x70, 0xB5, 0x14, 0x46, 0x00, 0x20, 0x05, 0xF0, + 0xAB, 0xFA, 0x00, 0xF0, + 0x01, 0x05, 0x01, 0x20, 0x05, 0xF0, 0xA6, 0xFA, 0x00, 0xF0, 0x01, 0x00, + 0x45, 0xEA, 0x00, 0x10, + 0x20, 0x70, 0x01, 0x20, 0x70, 0xBD, 0x80, 0x20, 0x10, 0x70, 0x01, 0x20, + 0x70, 0x47, 0x10, 0xB5, + 0x14, 0x46, 0xEF, 0xF7, 0x64, 0xF8, 0x53, 0x21, 0x21, 0x70, 0x54, 0x21, + 0x61, 0x70, 0x01, 0x0A, + 0xA1, 0x70, 0xE0, 0x70, 0xEF, 0xF7, 0x5F, 0xF8, 0x20, 0x71, 0x05, 0x20, + 0x10, 0xBD, 0x38, 0xB5, + 0x14, 0x46, 0x70, 0x4A, 0x13, 0x68, 0x59, 0x8E, 0x98, 0x8E, 0x93, 0xF8, + 0x36, 0x30, 0xDB, 0x07, + 0x0A, 0xD0, 0x03, 0x0A, 0x23, 0x70, 0x60, 0x70, 0x0D, 0x0A, 0xA5, 0x70, + 0xE1, 0x70, 0x23, 0x71, + 0x60, 0x71, 0xA5, 0x71, 0xE1, 0x71, 0x09, 0xE0, 0x0B, 0x0A, 0x23, 0x70, + 0x61, 0x70, 0x05, 0x0A, + 0xA5, 0x70, 0xE0, 0x70, 0x23, 0x71, 0x61, 0x71, 0xA5, 0x71, 0xE0, 0x71, + 0x10, 0x68, 0x90, 0xF8, + 0x31, 0x10, 0x21, 0x72, 0x10, 0xF8, 0x30, 0x1F, 0x61, 0x72, 0x90, 0xF8, + 0x31, 0x04, 0x8D, 0xF8, + 0x00, 0x00, 0x01, 0x21, 0x68, 0x46, 0xEF, 0xF7, 0x8E, 0xF9, 0xA0, 0x72, + 0x0B, 0x20, 0x38, 0xBD, + 0xA2, 0x20, 0x10, 0x70, 0x33, 0x20, 0x50, 0x70, 0x00, 0x20, 0x90, 0x70, + 0xD0, 0x70, 0x10, 0x71, + 0x50, 0x71, 0x06, 0x20, 0x70, 0x47, 0x08, 0xB5, 0x02, 0x23, 0x00, 0x93, + 0x52, 0x4B, 0x00, 0xF0, + 0x8D, 0xF8, 0x02, 0x20, 0x08, 0xBD, 0x08, 0xB5, 0x01, 0x23, 0x00, 0x93, + 0x4E, 0x4B, 0x9B, 0x1C, + 0x00, 0xF0, 0x84, 0xF8, 0x01, 0x20, 0x08, 0xBD, 0x08, 0xB5, 0x01, 0x23, + 0x00, 0x93, 0x4A, 0x4B, + 0xDB, 0x1C, 0x00, 0xF0, 0x7B, 0xF8, 0x01, 0x20, 0x08, 0xBD, 0x08, 0xB5, + 0x01, 0x23, 0x00, 0x93, + 0x45, 0x4B, 0x1B, 0x1D, 0x00, 0xF0, 0x72, 0xF8, 0x01, 0x20, 0x08, 0xBD, + 0x08, 0xB5, 0x01, 0x23, + 0x00, 0x93, 0x41, 0x4B, 0x5B, 0x1D, 0x00, 0xF0, 0x69, 0xF8, 0x01, 0x20, + 0x08, 0xBD, 0x08, 0xB5, + 0x01, 0x23, 0x00, 0x93, 0x3C, 0x4B, 0x9B, 0x1D, 0x00, 0xF0, 0x60, 0xF8, + 0x01, 0x20, 0x08, 0xBD, + 0x08, 0xB5, 0x02, 0x23, 0x00, 0x93, 0x38, 0x4B, 0xDB, 0x1D, 0x00, 0xF0, + 0x57, 0xF8, 0x02, 0x20, + 0x08, 0xBD, 0x08, 0xB5, 0x02, 0x23, 0x00, 0x93, 0x33, 0x4B, 0x09, 0x33, + 0x00, 0xF0, 0x4E, 0xF8, + 0x02, 0x20, 0x08, 0xBD, 0x08, 0xB5, 0x01, 0x23, 0x00, 0x93, 0x2F, 0x4B, + 0x0B, 0x33, 0x00, 0xF0, + 0x45, 0xF8, 0x01, 0x20, 0x08, 0xBD, 0x08, 0xB5, 0x01, 0x23, 0x00, 0x93, + 0x2A, 0x4B, 0x0C, 0x33, + 0x00, 0xF0, 0x3C, 0xF8, 0x01, 0x20, 0x08, 0xBD, 0x08, 0xB5, 0x01, 0x23, + 0x00, 0x93, 0x26, 0x4B, + 0x0D, 0x33, 0x00, 0xF0, 0x33, 0xF8, 0x01, 0x20, 0x08, 0xBD, 0x2D, 0xE9, + 0xF0, 0x41, 0x0F, 0x46, + 0x04, 0x46, 0x00, 0x78, 0x49, 0x1E, 0xCE, 0xB2, 0x00, 0x25, 0x63, 0x1C, + 0xA0, 0xF1, 0x20, 0x01, + 0x04, 0x29, 0x09, 0xD8, 0x1D, 0x49, 0x01, 0xEB, 0x80, 0x00, 0x31, 0x46, + 0x50, 0xF8, 0x80, 0x4C, + 0x18, 0x46, 0xA0, 0x47, 0x05, 0x46, 0x16, 0xE0, 0xA0, 0xF1, 0x30, 0x01, + 0x0B, 0x29, 0x12, 0xD8, + 0x16, 0x49, 0x14, 0x31, 0x01, 0xEB, 0x80, 0x00, 0x31, 0x46, 0x50, 0xF8, + 0xC0, 0x5C, 0x18, 0x46, + 0xA8, 0x47, 0x05, 0x46, 0x3E, 0xB1, 0x39, 0x46, 0x20, 0x46, 0xFF, 0xF7, + 0xD5, 0xFE, 0x01, 0x21, + 0x03, 0x20, 0xEE, 0xF7, 0xA6, 0xFA, 0x28, 0x46, 0xBD, 0xE8, 0xF0, 0x81, + 0x70, 0xB5, 0x1D, 0x46, + 0x04, 0x9C, 0x16, 0x46, 0x39, 0xB1, 0xA1, 0x42, 0x00, 0xD9, 0x21, 0x46, + 0x0A, 0x46, 0x01, 0x46, + 0x18, 0x46, 0x05, 0xF0, 0x8A, 0xF8, 0x22, 0x46, 0x29, 0x46, 0x30, 0x46, + 0xBD, 0xE8, 0x70, 0x40, + 0x05, 0xF0, 0x83, 0xB8, 0x4C, 0x07, 0x10, 0x00, 0xF0, 0x4F, 0x10, 0x00, + 0x90, 0x7B, 0x01, 0x00, + 0x10, 0xB5, 0x4F, 0xF4, 0x86, 0x71, 0x46, 0x48, 0x05, 0xF0, 0x18, 0xF9, + 0x44, 0x49, 0x01, 0x20, + 0xC1, 0xF8, 0x04, 0x01, 0x43, 0x49, 0x00, 0x20, 0x08, 0x70, 0x05, 0xF0, + 0xA1, 0xF9, 0x00, 0x21, + 0xBD, 0xE8, 0x10, 0x40, 0x01, 0x20, 0xEF, 0xF7, 0x20, 0xB9, 0x10, 0xB5, + 0x72, 0xB6, 0x00, 0x20, + 0x3C, 0x49, 0x08, 0x70, 0x05, 0xF0, 0x94, 0xF9, 0x62, 0xB6, 0x10, 0xBD, + 0x10, 0xB5, 0x72, 0xB6, + 0x01, 0x20, 0x38, 0x49, 0x08, 0x70, 0x36, 0x48, 0xD0, 0xF8, 0x08, 0x01, + 0x08, 0xB1, 0x05, 0xF0, + 0x2B, 0xF9, 0x62, 0xB6, 0x10, 0xBD, 0x10, 0xB5, 0x72, 0xB6, 0x31, 0x49, + 0xD1, 0xF8, 0x08, 0x31, + 0xD1, 0xF8, 0x00, 0x21, 0x20, 0x2B, 0x07, 0xD2, 0x5B, 0x1C, 0x52, 0x1C, + 0x22, 0xF0, 0x20, 0x02, + 0xC1, 0xF8, 0x08, 0x31, 0xC1, 0xF8, 0x00, 0x21, 0x01, 0xEB, 0xC2, 0x02, + 0x03, 0x68, 0x13, 0x60, + 0x40, 0x68, 0x50, 0x60, 0x27, 0x48, 0x00, 0x78, 0x01, 0x28, 0x05, 0xD1, + 0xD1, 0xF8, 0x08, 0x01, + 0x01, 0x28, 0x01, 0xD1, 0x05, 0xF0, 0x08, 0xF9, 0x62, 0xB6, 0x10, 0xBD, + 0x20, 0x4A, 0xD2, 0xF8, + 0x08, 0x01, 0x00, 0x28, 0x0E, 0xD0, 0xD2, 0xF8, 0x04, 0x01, 0x02, 0xEB, + 0xC0, 0x00, 0xC3, 0x79, + 0x23, 0xF0, 0x3F, 0x03, 0xC3, 0x71, 0x92, 0xF8, 0x08, 0x21, 0x52, 0x1E, + 0x02, 0xF0, 0x3F, 0x02, + 0x13, 0x43, 0xC3, 0x71, 0x70, 0x47, 0x10, 0xB5, 0x72, 0xB6, 0x15, 0x48, + 0xD0, 0xF8, 0x08, 0x11, + 0x59, 0xB1, 0x49, 0x1E, 0xC0, 0xF8, 0x08, 0x11, 0xD0, 0xF8, 0x04, 0x21, + 0x02, 0xF1, 0x01, 0x02, + 0x22, 0xF0, 0x20, 0x02, 0xC0, 0xF8, 0x04, 0x21, 0x05, 0xD1, 0x0E, 0x48, + 0x00, 0x78, 0x01, 0x28, + 0x01, 0xD1, 0x05, 0xF0, 0x35, 0xF9, 0x62, 0xB6, 0x10, 0xBD, 0x10, 0xB5, + 0x72, 0xB6, 0x00, 0x21, + 0x07, 0x48, 0xC0, 0xF8, 0x08, 0x11, 0xC0, 0xF8, 0x00, 0x11, 0x01, 0x21, + 0xC0, 0xF8, 0x04, 0x11, + 0x04, 0x48, 0x00, 0x78, 0x01, 0x28, 0x01, 0xD1, 0x05, 0xF0, 0x22, 0xF9, + 0x62, 0xB6, 0x10, 0xBD, + 0x68, 0x42, 0x01, 0x20, 0x37, 0x07, 0x10, 0x00, 0x18, 0x49, 0x00, 0x22, + 0x0A, 0x80, 0x4A, 0x80, + 0x4F, 0xF4, 0x70, 0x42, 0x8A, 0x80, 0x16, 0x4A, 0xCA, 0x80, 0x16, 0x4A, + 0x0A, 0x81, 0x16, 0x4A, + 0xC0, 0xE9, 0x00, 0x21, 0x05, 0x21, 0x01, 0x72, 0x70, 0x47, 0x1C, 0xB5, + 0x12, 0x49, 0xAD, 0xF8, + 0x04, 0x00, 0x02, 0x20, 0x8D, 0xF8, 0x06, 0x00, 0x04, 0x20, 0x09, 0x1F, + 0x8D, 0xF8, 0x07, 0x00, + 0x00, 0x91, 0x68, 0x46, 0xEF, 0xF7, 0x4B, 0xF9, 0x1C, 0xBD, 0x30, 0xB4, + 0x03, 0x46, 0x0A, 0x4A, + 0x00, 0x20, 0x14, 0x78, 0x9C, 0x42, 0x02, 0xD1, 0x30, 0xBC, 0xEF, 0xF7, + 0x76, 0xB9, 0x40, 0x1C, + 0xC0, 0xB2, 0x52, 0x1D, 0x05, 0x28, 0xF4, 0xD3, 0x30, 0xBC, 0x70, 0x47, + 0xFE, 0x4F, 0x10, 0x00, + 0x14, 0xA6, 0x01, 0x20, 0x6C, 0xA2, 0x01, 0x20, 0xD4, 0x7B, 0x01, 0x00, + 0x10, 0xB5, 0x88, 0xB3, + 0xA3, 0x49, 0xA4, 0x4A, 0x09, 0x78, 0x37, 0x29, 0x71, 0xD0, 0x11, 0xDC, + 0xA1, 0xF1, 0x20, 0x01, + 0x17, 0x29, 0x2C, 0xD2, 0xDF, 0xE8, 0x01, 0xF0, 0x6B, 0x6B, 0x6B, 0x6B, + 0x6B, 0x2B, 0x2B, 0x2B, + 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x2B, 0x6B, 0x6B, 0x6B, 0x6B, + 0x6B, 0x6B, 0x6B, 0x00, + 0x97, 0x4B, 0x70, 0x29, 0x5B, 0x78, 0x26, 0xD0, 0x0C, 0xDC, 0x3B, 0x29, + 0x57, 0xD0, 0x04, 0xDC, + 0x38, 0x29, 0x54, 0xD0, 0x3A, 0x29, 0x12, 0xD1, 0x51, 0xE0, 0x60, 0x29, + 0x19, 0xD0, 0x61, 0x29, + 0x0D, 0xD1, 0x16, 0xE0, 0x73, 0x29, 0x28, 0xD0, 0x05, 0xDC, 0x71, 0x29, + 0x15, 0xD0, 0x72, 0x29, + 0x05, 0xD1, 0x14, 0xE0, 0x0B, 0xE0, 0x85, 0x29, 0x0B, 0xD0, 0x86, 0x29, + 0x09, 0xD0, 0xC1, 0xB2, + 0x87, 0x48, 0xFF, 0xF7, 0xA9, 0xFD, 0x01, 0x21, 0x03, 0x20, 0xEE, 0xF7, + 0x7A, 0xF9, 0x00, 0x20, + 0x10, 0xBD, 0x02, 0x20, 0x10, 0xBD, 0x93, 0x70, 0xF9, 0xE7, 0xD3, 0x70, + 0xF7, 0xE7, 0x90, 0x78, + 0x01, 0x28, 0x08, 0xD0, 0x00, 0x28, 0xF2, 0xD1, 0x7F, 0x48, 0x81, 0xB2, + 0x5F, 0xF0, 0x72, 0x00, + 0xFF, 0xF7, 0x93, 0xFF, 0xEB, 0xE7, 0x7D, 0x48, 0xF7, 0xE7, 0xD0, 0x78, + 0x01, 0x28, 0x05, 0xD0, + 0x00, 0x28, 0xE4, 0xD1, 0x7A, 0x48, 0x81, 0xB2, 0x73, 0x20, 0xF1, 0xE7, + 0x79, 0x4C, 0x7A, 0x49, + 0x20, 0x68, 0x90, 0xF8, 0x31, 0x00, 0x42, 0x00, 0x71, 0x48, 0x10, 0x30, + 0x04, 0xF0, 0x45, 0xFF, + 0x20, 0x68, 0x10, 0xF8, 0x30, 0x1F, 0x4A, 0x00, 0x6D, 0x49, 0x40, 0x78, + 0x10, 0x31, 0x01, 0xEB, + 0x40, 0x00, 0x72, 0x49, 0x04, 0xF0, 0x39, 0xFF, 0x69, 0x48, 0x10, 0x30, + 0xE3, 0xE7, 0xC1, 0xB2, + 0x52, 0x68, 0x67, 0x48, 0xFF, 0xF7, 0x69, 0xFE, 0x6D, 0x49, 0x08, 0x70, + 0x01, 0x20, 0x10, 0xBD, + 0x2D, 0xE9, 0xF0, 0x5F, 0xDF, 0xF8, 0x88, 0xB1, 0x62, 0x4E, 0x62, 0x4D, + 0x89, 0x46, 0x07, 0x46, + 0x4F, 0xF0, 0x01, 0x0A, 0xAB, 0xF1, 0x10, 0x0B, 0x08, 0x36, 0x28, 0x78, + 0xA8, 0x46, 0x04, 0x46, + 0x07, 0x28, 0x76, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x04, 0x21, 0x25, 0x40, + 0x5C, 0x78, 0x8A, 0x00, + 0x01, 0x2F, 0x02, 0xD0, 0x02, 0x2F, 0x0C, 0xD0, 0x6B, 0xE0, 0x48, 0x46, + 0xFF, 0xF7, 0x5E, 0xFF, + 0x02, 0x28, 0x02, 0xD0, 0x01, 0x28, 0x02, 0xD0, 0x63, 0xE0, 0x03, 0x24, + 0x61, 0xE0, 0x02, 0x24, + 0x5F, 0xE0, 0x68, 0x78, 0x01, 0x28, 0x04, 0xD0, 0x4D, 0x48, 0x10, 0x21, + 0x10, 0x38, 0x04, 0xF0, + 0x7B, 0xFF, 0x54, 0x46, 0x86, 0xF8, 0x00, 0xA0, 0x53, 0xE0, 0x02, 0x2F, + 0x4F, 0xD0, 0x00, 0x24, + 0x39, 0xE0, 0x02, 0x2F, 0x1A, 0xD1, 0x4E, 0x4C, 0x45, 0x48, 0xD8, 0xF8, + 0x04, 0x10, 0x22, 0x78, + 0x10, 0x38, 0x04, 0xF0, 0xEA, 0xFE, 0x03, 0x20, 0x30, 0x70, 0x20, 0x78, + 0xB0, 0x80, 0x98, 0xF8, + 0x00, 0x00, 0x04, 0x24, 0x88, 0xF8, 0x01, 0x00, 0x88, 0xF8, 0x00, 0x40, + 0x27, 0xE0, 0x00, 0x24, + 0x88, 0xF8, 0x01, 0x00, 0x2C, 0x70, 0xB8, 0xE7, 0x02, 0x2F, 0x02, 0xD0, + 0x01, 0x2F, 0xF6, 0xD0, + 0x2F, 0xE0, 0xFF, 0xF7, 0xA3, 0xFE, 0x08, 0x21, 0x28, 0xB1, 0x02, 0x22, + 0x32, 0x70, 0x70, 0x80, + 0xB1, 0x80, 0x05, 0x24, 0x25, 0xE0, 0x68, 0x78, 0x06, 0x28, 0x04, 0xD0, + 0x00, 0x22, 0xCB, 0xF8, + 0x00, 0x20, 0xCB, 0xF8, 0x04, 0x20, 0x03, 0x20, 0x30, 0x70, 0xB1, 0x80, + 0x06, 0x24, 0x18, 0xE0, + 0x02, 0x2F, 0x08, 0xD0, 0x02, 0x24, 0xC0, 0xB2, 0x88, 0xF8, 0x01, 0x00, + 0x2C, 0x70, 0x29, 0x48, + 0x08, 0x30, 0xBD, 0xE8, 0xF0, 0x9F, 0x68, 0x78, 0x04, 0x28, 0x08, 0xD0, + 0x0B, 0xEB, 0x09, 0x00, + 0x49, 0x46, 0x10, 0xF8, 0x01, 0x2C, 0x22, 0x48, 0x10, 0x38, 0x04, 0xF0, + 0x1D, 0xFF, 0x86, 0xF8, + 0x00, 0xA0, 0xA8, 0x46, 0x28, 0x78, 0xE7, 0xE7, 0x02, 0x2F, 0x05, 0xD0, + 0xB9, 0xF1, 0x08, 0x0F, + 0x93, 0xD1, 0xFF, 0xF7, 0x80, 0xFE, 0x90, 0xE7, 0xFF, 0xF7, 0x7D, 0xFE, + 0x98, 0xF8, 0x00, 0x00, + 0x03, 0x24, 0x88, 0xF8, 0x01, 0x00, 0x88, 0xF8, 0x00, 0x40, 0x6E, 0xE7, + 0x02, 0x2F, 0x4F, 0xF0, + 0x03, 0x04, 0xAD, 0xD0, 0xCF, 0xE7, 0x13, 0x49, 0x00, 0x22, 0x0A, 0x70, + 0x4A, 0x70, 0x18, 0x4A, + 0x52, 0x1C, 0x4A, 0x60, 0x17, 0x49, 0x01, 0x60, 0x0D, 0x49, 0x10, 0x39, + 0x81, 0x80, 0x10, 0x31, + 0xC1, 0x80, 0x10, 0x21, 0x01, 0x81, 0x0E, 0x21, 0x13, 0x48, 0x04, 0xF0, + 0xF5, 0xBE, 0x10, 0xB5, + 0x04, 0x46, 0x04, 0xF0, 0xA5, 0xFF, 0x06, 0x48, 0x21, 0x68, 0x10, 0x38, + 0x01, 0x60, 0x61, 0x68, + 0x41, 0x60, 0x0E, 0x48, 0xFF, 0xF7, 0x91, 0xFE, 0xBD, 0xE8, 0x10, 0x40, + 0x04, 0xF0, 0x3C, 0xBF, + 0x84, 0x43, 0x01, 0x20, 0x38, 0x07, 0x10, 0x00, 0x14, 0xA6, 0x01, 0x20, + 0xEE, 0x35, 0x01, 0x20, + 0x6C, 0xA2, 0x01, 0x20, 0x4C, 0x07, 0x10, 0x00, 0x94, 0x0B, 0x01, 0x20, + 0xBE, 0x0B, 0x01, 0x20, + 0x08, 0x50, 0x10, 0x00, 0xB1, 0x22, 0x01, 0x00, 0xF0, 0x4F, 0x10, 0x00, + 0x74, 0x43, 0x00, 0x00, + 0x70, 0xB5, 0x04, 0x4D, 0x38, 0x21, 0x28, 0x46, 0x2C, 0x88, 0x04, 0xF0, + 0xC5, 0xFE, 0x64, 0x1C, + 0x2C, 0x80, 0x70, 0xBD, 0x0A, 0x44, 0x01, 0x20, 0x37, 0x48, 0x00, 0x21, + 0x01, 0x60, 0x41, 0x60, + 0x70, 0x47, 0xC0, 0xB2, 0x01, 0x22, 0x00, 0xF0, 0x48, 0xFA, 0xFE, 0xE7, + 0x34, 0x4C, 0x00, 0x25, + 0x32, 0x4F, 0xC4, 0xE9, 0x02, 0x25, 0xC4, 0xE9, 0x00, 0x71, 0x06, 0x46, + 0x00, 0x68, 0x20, 0x61, + 0x70, 0x68, 0x60, 0x61, 0xB0, 0x68, 0xA0, 0x61, 0xF0, 0x68, 0xE0, 0x61, + 0x30, 0x69, 0x20, 0x62, + 0x70, 0x69, 0x60, 0x62, 0xB0, 0x69, 0xA0, 0x62, 0xF0, 0x69, 0xE0, 0x62, + 0x29, 0x48, 0x90, 0x46, + 0x89, 0x46, 0x00, 0x68, 0x20, 0x63, 0x27, 0x48, 0x10, 0x38, 0x00, 0x68, + 0x60, 0x63, 0x25, 0x48, + 0x0C, 0x38, 0x00, 0x68, 0xA0, 0x63, 0x23, 0x48, 0x08, 0x38, 0x00, 0x68, + 0xE0, 0x63, 0x21, 0x48, + 0x00, 0x1D, 0x00, 0x68, 0x20, 0x64, 0x1F, 0x48, 0x34, 0x38, 0x00, 0x68, + 0x60, 0x64, 0x1D, 0x48, + 0x14, 0x38, 0x00, 0x68, 0xC4, 0xE9, 0x12, 0x05, 0xEE, 0xF7, 0x9B, 0xF9, + 0x20, 0x65, 0xC4, 0xE9, + 0x15, 0x65, 0xE5, 0x65, 0x25, 0x66, 0x65, 0x66, 0xA5, 0x66, 0xE5, 0x66, + 0x25, 0x67, 0x65, 0x67, + 0xC4, 0xE9, 0x1E, 0x57, 0x41, 0x46, 0x48, 0x46, 0xFF, 0xF7, 0xB3, 0xFF, + 0x10, 0xB5, 0x04, 0x46, + 0xC0, 0xB2, 0x00, 0x22, 0x00, 0xF0, 0xF9, 0xF9, 0x0F, 0x49, 0x08, 0x68, + 0x08, 0x28, 0x03, 0xDA, + 0x09, 0x4A, 0x14, 0x54, 0x40, 0x1C, 0x08, 0x60, 0x10, 0xBD, 0x01, 0x28, + 0x06, 0xD0, 0x02, 0x28, + 0x08, 0xD1, 0x00, 0x22, 0x11, 0x46, 0x13, 0x20, 0x00, 0xF0, 0xE7, 0xB9, + 0x00, 0x22, 0x11, 0x46, + 0x12, 0x20, 0xF9, 0xE7, 0x70, 0x47, 0x00, 0x00, 0x70, 0xEF, 0x01, 0x20, + 0xAF, 0x05, 0x50, 0xFA, + 0x80, 0xEF, 0x01, 0x20, 0x38, 0xED, 0x00, 0xE0, 0x48, 0x07, 0x10, 0x00, + 0x2D, 0xE9, 0xF0, 0x41, + 0x40, 0xF2, 0x02, 0x71, 0xB9, 0x48, 0x04, 0xF0, 0x3F, 0xFE, 0xB8, 0x4C, + 0x01, 0x26, 0x00, 0x25, + 0x66, 0x70, 0xA5, 0x80, 0xA5, 0x71, 0x02, 0x20, 0xE0, 0x71, 0xEE, 0xF7, + 0xAC, 0xFC, 0x20, 0x81, + 0xEE, 0xF7, 0xA5, 0xFC, 0x07, 0x02, 0xEE, 0xF7, 0xA2, 0xFC, 0x47, 0xEA, + 0x10, 0x20, 0x60, 0x81, + 0x4A, 0xF2, 0x33, 0x20, 0x20, 0x82, 0x30, 0x02, 0x60, 0x82, 0xAD, 0x48, + 0x00, 0x68, 0x41, 0x8A, + 0xA1, 0x82, 0x01, 0x8A, 0xE1, 0x82, 0xC1, 0x8A, 0x21, 0x83, 0x81, 0x8A, + 0x61, 0x83, 0x90, 0xF8, + 0xDE, 0x10, 0x21, 0x77, 0xA7, 0x49, 0x09, 0x68, 0x09, 0x7E, 0x61, 0x77, + 0x90, 0xF8, 0xA0, 0x10, + 0x01, 0xF0, 0x01, 0x01, 0xA1, 0x77, 0x81, 0x69, 0x21, 0x63, 0xC1, 0x69, + 0x61, 0x63, 0xA5, 0x63, + 0xE5, 0x63, 0xA4, 0xF8, 0x40, 0x50, 0x84, 0xF8, 0x42, 0x50, 0x84, 0xF8, + 0x43, 0x60, 0x41, 0x8E, + 0xA4, 0xF8, 0x50, 0x10, 0x81, 0x8E, 0xA4, 0xF8, 0x52, 0x10, 0x90, 0xF8, + 0x31, 0x10, 0x84, 0xF8, + 0x54, 0x10, 0x90, 0xF8, 0x30, 0x10, 0x84, 0xF8, 0x55, 0x10, 0x01, 0x21, + 0x00, 0xF2, 0x61, 0x40, + 0xEE, 0xF7, 0xC9, 0xFD, 0x84, 0xF8, 0x56, 0x00, 0x93, 0x48, 0xA4, 0xF8, + 0x80, 0x00, 0x93, 0x48, + 0xA4, 0xF8, 0x88, 0x00, 0x92, 0x48, 0xA4, 0xF8, 0x8A, 0x00, 0x92, 0x48, + 0xA4, 0xF8, 0x8C, 0x00, + 0x91, 0x48, 0xA4, 0xF8, 0x8E, 0x00, 0x91, 0x48, 0xA4, 0xF8, 0x90, 0x00, + 0x90, 0x48, 0xA4, 0xF8, + 0x92, 0x00, 0x90, 0x48, 0xA4, 0xF8, 0x94, 0x00, 0x8F, 0x48, 0xA4, 0xF8, + 0x96, 0x00, 0x8F, 0x48, + 0xA4, 0xF8, 0x98, 0x00, 0x8E, 0x48, 0xA4, 0xF8, 0x9A, 0x00, 0x8E, 0x48, + 0xA4, 0xF8, 0x9C, 0x00, + 0x8D, 0x48, 0xA4, 0xF8, 0x9E, 0x00, 0x8D, 0x48, 0xA4, 0xF8, 0xA0, 0x00, + 0x8C, 0x48, 0xA4, 0xF8, + 0xA2, 0x00, 0x8C, 0x48, 0xA4, 0xF8, 0xA4, 0x00, 0x8C, 0x49, 0x8B, 0x48, + 0xA4, 0xF8, 0xA6, 0x00, + 0x48, 0x88, 0x40, 0x1C, 0x48, 0x80, 0xA5, 0x22, 0x22, 0x70, 0x66, 0x70, + 0x60, 0x80, 0x0E, 0x70, + 0xBD, 0xE8, 0xF0, 0x81, 0x70, 0xB5, 0x85, 0x4C, 0x05, 0x46, 0x00, 0x23, + 0x60, 0x88, 0x6F, 0x49, + 0x40, 0x1C, 0x82, 0xB2, 0x62, 0x80, 0x28, 0x46, 0x01, 0xF0, 0x80, 0xFA, + 0x25, 0x70, 0x70, 0xBD, + 0x70, 0xB5, 0x05, 0x46, 0x40, 0xF2, 0x02, 0x71, 0x68, 0x48, 0x04, 0xF0, + 0x9D, 0xFD, 0x7B, 0x4C, + 0x66, 0x49, 0x60, 0x88, 0x40, 0x1C, 0x82, 0xB2, 0x62, 0x80, 0x28, 0x46, + 0x01, 0xF0, 0xA6, 0xFA, + 0x25, 0x70, 0x70, 0xBD, 0x2D, 0xE9, 0xF0, 0x41, 0x74, 0x4C, 0x05, 0x46, + 0x20, 0x78, 0xA8, 0x42, + 0x04, 0xD0, 0x40, 0xF2, 0x02, 0x71, 0x5D, 0x48, 0x04, 0xF0, 0x86, 0xFD, + 0x70, 0x49, 0x65, 0x70, + 0x0F, 0x20, 0x08, 0x60, 0x5A, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x61, 0x24, + 0x0A, 0xB1, 0x1F, 0x22, + 0x0A, 0x60, 0x56, 0x49, 0x55, 0x4D, 0x10, 0x31, 0x61, 0x60, 0x38, 0x21, + 0x29, 0x71, 0x05, 0xF1, + 0x48, 0x03, 0xA3, 0x60, 0x90, 0xF8, 0x31, 0x20, 0x90, 0xF8, 0x30, 0x60, + 0x6A, 0x71, 0x02, 0xFB, + 0x06, 0xF1, 0x03, 0xEB, 0x41, 0x07, 0xAE, 0x71, 0xE7, 0x60, 0xEA, 0x71, + 0x11, 0x44, 0x03, 0xEB, + 0x41, 0x02, 0x22, 0x61, 0x31, 0x44, 0x2E, 0x72, 0x03, 0xEB, 0x41, 0x01, + 0x61, 0x61, 0x01, 0x21, + 0x00, 0xF2, 0x61, 0x40, 0xEE, 0xF7, 0x2F, 0xFD, 0x68, 0x72, 0xA1, 0xE7, + 0x2D, 0xE9, 0xF0, 0x41, + 0x05, 0x46, 0x56, 0x4C, 0x17, 0x46, 0x88, 0x46, 0xC0, 0x07, 0x04, 0xD0, + 0x38, 0x22, 0x42, 0x49, + 0x60, 0x68, 0x04, 0xF0, 0xCA, 0xFC, 0x3E, 0x4E, 0xA8, 0x07, 0x12, 0xD5, + 0x31, 0x68, 0x91, 0xF8, + 0x31, 0x00, 0x91, 0xF8, 0x30, 0x10, 0x48, 0x43, 0x61, 0x78, 0x30, 0x29, + 0x3E, 0xD0, 0x31, 0x29, + 0x3E, 0xD0, 0x32, 0x29, 0x42, 0xD0, 0x3B, 0x49, 0xA3, 0x68, 0x42, 0x00, + 0x18, 0x46, 0x04, 0xF0, + 0xB4, 0xFC, 0x68, 0x07, 0x0E, 0xD5, 0x30, 0x68, 0x90, 0xF8, 0x31, 0x20, + 0x60, 0x78, 0x30, 0x28, + 0x36, 0xD0, 0x31, 0x28, 0x36, 0xD0, 0x32, 0x28, 0x39, 0xD0, 0x36, 0x49, + 0x52, 0x00, 0xE0, 0x68, + 0x04, 0xF0, 0xA3, 0xFC, 0x28, 0x07, 0x0F, 0xD5, 0x30, 0x68, 0x61, 0x78, + 0x90, 0xF8, 0x30, 0x00, + 0x30, 0x29, 0x2E, 0xD0, 0x31, 0x29, 0x2E, 0xD0, 0x32, 0x29, 0x31, 0xD0, + 0x31, 0x49, 0x23, 0x69, + 0x42, 0x00, 0x18, 0x46, 0x04, 0xF0, 0x91, 0xFC, 0xE8, 0x06, 0x31, 0xD5, + 0x1F, 0x48, 0x42, 0x7A, + 0x60, 0x78, 0x30, 0x28, 0x26, 0xD0, 0x31, 0x28, 0x26, 0xD0, 0x32, 0x28, + 0x26, 0xD0, 0x2D, 0x49, + 0x60, 0x69, 0xBD, 0xE8, 0xF0, 0x41, 0x52, 0x00, 0x04, 0xF0, 0x7F, 0xBC, + 0x1B, 0x49, 0xC3, 0xE7, + 0x1B, 0x49, 0xB8, 0xF1, 0x00, 0x0F, 0xBF, 0xD0, 0x2A, 0x49, 0xBD, 0xE7, + 0x1A, 0x49, 0xBB, 0xE7, + 0x1A, 0x49, 0xCB, 0xE7, 0x1A, 0x49, 0x00, 0x2F, 0xC8, 0xD0, 0x27, 0x49, + 0xC6, 0xE7, 0x1A, 0x49, + 0xC4, 0xE7, 0x1A, 0x49, 0xD3, 0xE7, 0x1A, 0x49, 0x00, 0x2F, 0xD0, 0xD0, + 0x23, 0x49, 0xCE, 0xE7, + 0x19, 0x49, 0xCC, 0xE7, 0x19, 0x49, 0xDB, 0xE7, 0x19, 0x49, 0xD9, 0xE7, + 0x1A, 0x49, 0xD7, 0xE7, + 0x26, 0xE7, 0x06, 0x4A, 0xA5, 0x20, 0x10, 0x70, 0x18, 0x48, 0x41, 0x78, + 0x51, 0x70, 0x01, 0x70, + 0x41, 0x88, 0x49, 0x1C, 0x41, 0x80, 0x51, 0x80, 0x70, 0x47, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x20, + 0x4C, 0x07, 0x10, 0x00, 0x50, 0x07, 0x10, 0x00, 0x0A, 0x44, 0x01, 0x20, + 0x14, 0xA6, 0x01, 0x20, + 0xB2, 0x2F, 0x01, 0x20, 0xEE, 0x35, 0x01, 0x20, 0x42, 0x44, 0x01, 0x20, + 0x04, 0xA3, 0x01, 0x20, + 0x1E, 0x0B, 0x01, 0x20, 0x94, 0x0B, 0x01, 0x20, 0x7E, 0x4A, 0x01, 0x20, + 0x2E, 0xA3, 0x01, 0x20, + 0x48, 0x0B, 0x01, 0x20, 0xBE, 0x0B, 0x01, 0x20, 0xA8, 0x4A, 0x01, 0x20, + 0xB8, 0xA4, 0x01, 0x20, + 0xA2, 0x1C, 0x01, 0x20, 0xAA, 0x1C, 0x01, 0x20, 0xF4, 0x4A, 0x01, 0x20, + 0x94, 0x07, 0x10, 0x00, + 0x68, 0x07, 0x10, 0x00, 0x4A, 0x0C, 0x01, 0x20, 0x92, 0x09, 0x01, 0x20, + 0xBC, 0x09, 0x01, 0x20, + 0x1F, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xA0, 0x00, 0xC0, 0x07, 0x01, 0xD0, + 0x00, 0xF0, 0x3A, 0xB8, + 0x00, 0xF0, 0xDC, 0xB8, 0x1A, 0x49, 0x09, 0x68, 0x91, 0xF8, 0xA0, 0x10, + 0xC9, 0x07, 0x02, 0xD0, + 0xC0, 0xB2, 0x00, 0xF0, 0x39, 0xB8, 0x01, 0x46, 0x00, 0x20, 0x00, 0xF0, + 0x2C, 0xB9, 0x38, 0xB5, + 0x04, 0x46, 0x69, 0x46, 0x18, 0x30, 0x00, 0xF0, 0xA2, 0xFD, 0x11, 0x48, + 0x00, 0x99, 0x00, 0x68, + 0x90, 0xF8, 0xA0, 0x00, 0xC0, 0x07, 0x20, 0x46, 0x02, 0xD0, 0x00, 0xF0, + 0x44, 0xF8, 0x38, 0xBD, + 0x00, 0xF0, 0xC6, 0xF8, 0x38, 0xBD, 0x00, 0xF0, 0x24, 0xB9, 0x09, 0x4B, + 0x1B, 0x68, 0x93, 0xF8, + 0xA0, 0x30, 0xDB, 0x07, 0x01, 0xD1, 0x00, 0xF0, 0x3A, 0xB9, 0x70, 0x47, + 0x04, 0x4A, 0x12, 0x68, + 0x92, 0xF8, 0xA0, 0x20, 0x52, 0x07, 0x01, 0xD5, 0x00, 0xF0, 0x43, 0xB9, + 0x70, 0x47, 0x00, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x1C, 0xB5, 0x4F, 0x49, 0xD1, 0xE9, 0x00, 0x01, + 0xCD, 0xE9, 0x00, 0x01, + 0x68, 0x46, 0xFF, 0xF7, 0x80, 0xFB, 0x1C, 0xBD, 0x1C, 0xB5, 0x4A, 0x4A, + 0xD2, 0xE9, 0x02, 0x12, + 0xCD, 0xE9, 0x00, 0x12, 0x8D, 0xF8, 0x02, 0x00, 0x68, 0x46, 0xFF, 0xF7, + 0x74, 0xFB, 0x1C, 0xBD, + 0x88, 0x42, 0x0E, 0xD9, 0x90, 0x42, 0x01, 0xD3, 0xFF, 0x20, 0x70, 0x47, + 0x91, 0x42, 0x08, 0xD0, + 0x40, 0x1A, 0xC0, 0xEB, 0x00, 0x20, 0x51, 0x1A, 0xB0, 0xFB, 0xF1, 0xF0, + 0x10, 0xF0, 0xFF, 0x00, + 0xF3, 0xD1, 0x01, 0x20, 0x70, 0x47, 0x7C, 0xB5, 0x05, 0x46, 0x00, 0x20, + 0x00, 0x90, 0x01, 0x90, + 0x95, 0xF8, 0x4D, 0x21, 0x9D, 0xF8, 0x00, 0x00, 0x62, 0xF3, 0x85, 0x00, + 0x8D, 0xF8, 0x00, 0x00, + 0x95, 0xF8, 0x3E, 0x21, 0x03, 0x2A, 0x3E, 0xD0, 0x08, 0x2A, 0x40, 0xD0, + 0x20, 0xF0, 0xC0, 0x00, + 0x10, 0xF1, 0x80, 0x00, 0x8D, 0xF8, 0x00, 0x00, 0x0A, 0x14, 0x10, 0x09, + 0x8D, 0xF8, 0x01, 0x00, + 0x9D, 0xF8, 0x03, 0x00, 0x2C, 0x4E, 0x62, 0xF3, 0x07, 0x10, 0x0A, 0x09, + 0x8D, 0xF8, 0x02, 0x20, + 0x61, 0xF3, 0x03, 0x00, 0x8D, 0xF8, 0x03, 0x00, 0x30, 0x68, 0xB0, 0xF8, + 0xA3, 0x20, 0xB0, 0xF8, + 0xA1, 0x10, 0x35, 0xF8, 0x4A, 0x0F, 0xFF, 0xF7, 0xBB, 0xFF, 0x8D, 0xF8, + 0x04, 0x00, 0x30, 0x68, + 0xB0, 0xF8, 0xA7, 0x20, 0xB0, 0xF8, 0xA5, 0x10, 0x68, 0x88, 0xFF, 0xF7, + 0xB1, 0xFF, 0x8D, 0xF8, + 0x05, 0x00, 0x29, 0x7A, 0x9D, 0xF8, 0x06, 0x00, 0x61, 0xF3, 0x05, 0x00, + 0x8D, 0xF8, 0x06, 0x00, + 0x95, 0xF8, 0xF6, 0x10, 0x09, 0x29, 0x1E, 0xD2, 0xDF, 0xE8, 0x01, 0xF0, + 0x0C, 0x0E, 0x10, 0x12, + 0x14, 0x16, 0x18, 0x1A, 0x1C, 0x00, 0x20, 0xF0, 0xC0, 0x00, 0x40, 0x30, + 0xC2, 0xE7, 0x40, 0xF0, + 0xC0, 0x00, 0xBF, 0xE7, 0x00, 0x24, 0x0E, 0xE0, 0x01, 0x24, 0x0C, 0xE0, + 0x02, 0x24, 0x0A, 0xE0, + 0x03, 0x24, 0x08, 0xE0, 0x04, 0x24, 0x06, 0xE0, 0x05, 0x24, 0x04, 0xE0, + 0x06, 0x24, 0x02, 0xE0, + 0x07, 0x24, 0x00, 0xE0, 0x08, 0x24, 0xA1, 0x08, 0x61, 0xF3, 0x87, 0x10, + 0x8D, 0xF8, 0x06, 0x00, + 0x9D, 0xF8, 0x07, 0x00, 0x64, 0xF3, 0x87, 0x10, 0x8D, 0xF8, 0x07, 0x00, + 0x68, 0x46, 0xFF, 0xF7, + 0xEA, 0xFA, 0x7C, 0xBD, 0xF0, 0x7B, 0x01, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x1C, 0xB5, 0x54, 0x49, + 0xD1, 0xE9, 0x00, 0x01, 0xCD, 0xE9, 0x00, 0x01, 0x68, 0x46, 0xFF, 0xF7, + 0xDC, 0xFA, 0x1C, 0xBD, + 0x1C, 0xB5, 0x4F, 0x4B, 0xD3, 0xE9, 0x02, 0x23, 0xCD, 0xE9, 0x00, 0x23, + 0x90, 0xF8, 0x3E, 0x21, + 0x03, 0x2A, 0x19, 0xD0, 0x08, 0x2A, 0x9D, 0xF8, 0x00, 0x20, 0x22, 0xF0, + 0xF0, 0x02, 0x19, 0xD0, + 0x12, 0xF1, 0x20, 0x02, 0x8D, 0xF8, 0x00, 0x20, 0x90, 0xF8, 0x3F, 0x21, + 0x02, 0xF0, 0x0F, 0x02, + 0x01, 0x2A, 0x11, 0xD0, 0x02, 0x2A, 0x15, 0xD0, 0x04, 0x2A, 0x9D, 0xF8, + 0x01, 0x20, 0x22, 0xF0, + 0x0F, 0x02, 0x2E, 0xD0, 0x52, 0x1C, 0x12, 0xE0, 0x9D, 0xF8, 0x00, 0x20, + 0x22, 0xF0, 0xF0, 0x02, + 0x10, 0x32, 0xE7, 0xE7, 0x30, 0x32, 0xE5, 0xE7, 0x9D, 0xF8, 0x01, 0x20, + 0x22, 0xF0, 0x0F, 0x02, + 0x92, 0x1C, 0x04, 0xE0, 0x9D, 0xF8, 0x01, 0x20, 0x22, 0xF0, 0x0F, 0x02, + 0xD2, 0x1C, 0x8D, 0xF8, + 0x01, 0x20, 0x90, 0xF8, 0x4D, 0x01, 0xD2, 0xB2, 0x60, 0xF3, 0x07, 0x12, + 0x8D, 0xF8, 0x01, 0x20, + 0xBD, 0xF8, 0x02, 0x00, 0x0A, 0x0C, 0x62, 0xF3, 0x0B, 0x00, 0xAD, 0xF8, + 0x02, 0x00, 0xBD, 0xF8, + 0x03, 0x00, 0x61, 0xF3, 0x0F, 0x10, 0xAD, 0xF8, 0x03, 0x00, 0x68, 0x46, + 0xFF, 0xF7, 0x8B, 0xFA, + 0x1C, 0xBD, 0x12, 0x1D, 0xE3, 0xE7, 0x1C, 0xB5, 0x25, 0x4B, 0xD3, 0xE9, + 0x04, 0x23, 0xCD, 0xE9, + 0x00, 0x23, 0x8D, 0xF8, 0x01, 0x00, 0xCD, 0xF8, 0x02, 0x10, 0x68, 0x46, + 0xFF, 0xF7, 0x7B, 0xFA, + 0x1C, 0xBD, 0x1C, 0xB5, 0x1F, 0x4A, 0x12, 0x68, 0x92, 0xF8, 0xA0, 0x20, + 0x93, 0x07, 0x15, 0xD5, + 0x08, 0x28, 0x13, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x12, 0x04, 0x06, 0x06, + 0x06, 0x06, 0x06, 0x06, + 0x12, 0x06, 0x0B, 0xD5, 0x16, 0x4B, 0xD3, 0xE9, 0x06, 0x23, 0xCD, 0xE9, + 0x00, 0x23, 0x8D, 0xF8, + 0x01, 0x00, 0xCD, 0xF8, 0x02, 0x10, 0x68, 0x46, 0xFF, 0xF7, 0x5D, 0xFA, + 0x1C, 0xBD, 0x1C, 0xB5, + 0x0F, 0x4C, 0xD4, 0xE9, 0x08, 0x34, 0xCD, 0xE9, 0x00, 0x34, 0x8D, 0xF8, + 0x01, 0x00, 0xCD, 0xF8, + 0x02, 0x10, 0x68, 0x46, 0x12, 0xB1, 0xFF, 0xF7, 0x2A, 0xFC, 0x1C, 0xBD, + 0xFF, 0xF7, 0x4B, 0xFA, + 0x1C, 0xBD, 0x1C, 0xB5, 0x06, 0x4B, 0xD3, 0xE9, 0x0A, 0x23, 0xCD, 0xE9, + 0x00, 0x23, 0x8D, 0xF8, + 0x01, 0x00, 0xCD, 0xF8, 0x02, 0x10, 0x68, 0x46, 0xFF, 0xF7, 0x3D, 0xFA, + 0x1C, 0xBD, 0x00, 0x00, + 0x08, 0x7C, 0x01, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x2D, 0xE9, 0xFF, 0x41, + 0xED, 0xF7, 0xDC, 0xFB, + 0x23, 0x4D, 0x00, 0x24, 0xC4, 0xEB, 0xC4, 0x01, 0x05, 0xEB, 0x81, 0x00, + 0x00, 0xF1, 0x0C, 0x03, + 0x02, 0x7E, 0xC8, 0xCB, 0xCD, 0xE9, 0x02, 0x72, 0xCD, 0xE9, 0x00, 0x36, + 0xD0, 0xE9, 0x01, 0x23, + 0x55, 0xF8, 0x21, 0x00, 0x00, 0x21, 0xED, 0xF7, 0xB1, 0xFD, 0x18, 0xB1, + 0x21, 0x46, 0x43, 0x20, + 0xFF, 0xF7, 0x2F, 0xFC, 0x64, 0x1C, 0x05, 0x2C, 0xE4, 0xDB, 0x15, 0x4D, + 0x00, 0x24, 0x8C, 0x35, + 0x05, 0xEB, 0xC4, 0x00, 0x00, 0x21, 0x42, 0x68, 0x55, 0xF8, 0x34, 0x00, + 0xED, 0xF7, 0x25, 0xFD, + 0x18, 0xB1, 0x21, 0x46, 0x44, 0x20, 0xFF, 0xF7, 0x1C, 0xFC, 0x64, 0x1C, + 0x06, 0x2C, 0xEF, 0xDB, + 0x0B, 0x4D, 0x00, 0x24, 0x15, 0xF1, 0xBC, 0x05, 0x00, 0x21, 0x55, 0xF8, + 0x24, 0x00, 0xED, 0xF7, + 0x3A, 0xFC, 0x18, 0xB1, 0x21, 0x46, 0x45, 0x20, 0xFF, 0xF7, 0x0B, 0xFC, + 0x64, 0x1C, 0x04, 0x2C, + 0xF2, 0xDB, 0xBD, 0xE8, 0xFF, 0x81, 0x01, 0x46, 0x46, 0x20, 0xFF, 0xF7, + 0x02, 0xBC, 0x00, 0x00, + 0x38, 0x7C, 0x01, 0x00, 0x00, 0xF0, 0x1F, 0x03, 0x01, 0x22, 0x9A, 0x40, + 0x43, 0x09, 0x9B, 0x00, + 0x03, 0xF1, 0xE0, 0x23, 0xC3, 0xF8, 0x80, 0x22, 0x49, 0x07, 0x09, 0x0E, + 0x00, 0x28, 0x06, 0xDA, + 0x00, 0xF0, 0x0F, 0x00, 0x00, 0xF1, 0xE0, 0x20, 0x80, 0xF8, 0x14, 0x1D, + 0x03, 0xE0, 0x00, 0xF1, + 0xE0, 0x20, 0x80, 0xF8, 0x00, 0x14, 0xC3, 0xF8, 0x00, 0x21, 0x70, 0x47, + 0x2D, 0xE9, 0xF0, 0x41, + 0x64, 0x27, 0x07, 0x26, 0x00, 0x25, 0xFD, 0x4C, 0xFD, 0x48, 0xEE, 0xF7, + 0xF3, 0xF9, 0xFC, 0x48, + 0x03, 0x68, 0xD9, 0x1C, 0x3C, 0xD0, 0x42, 0x68, 0xD1, 0x1C, 0x39, 0xD0, + 0x81, 0x68, 0x11, 0xF1, + 0x03, 0x0F, 0x35, 0xD0, 0x00, 0x69, 0x10, 0xF1, 0x03, 0x0F, 0x31, 0xD0, + 0xB3, 0xF1, 0xFF, 0x3F, + 0x31, 0xD0, 0x13, 0xF1, 0x02, 0x0F, 0x2E, 0xD0, 0xB2, 0xF1, 0xFF, 0x3F, + 0x2B, 0xD0, 0x12, 0xF1, + 0x02, 0x0F, 0x28, 0xD0, 0xB1, 0xF1, 0xFF, 0x3F, 0x25, 0xD0, 0x11, 0xF1, + 0x02, 0x0F, 0x22, 0xD0, + 0xB0, 0xF1, 0xFF, 0x3F, 0x1F, 0xD0, 0x10, 0xF1, 0x02, 0x0F, 0x1C, 0xD0, + 0xDF, 0xB2, 0xD6, 0xB2, + 0xCD, 0xB2, 0x04, 0x46, 0x2A, 0x46, 0x31, 0x46, 0x38, 0x46, 0xEE, 0xF7, + 0xF1, 0xF8, 0x20, 0x46, + 0xEE, 0xF7, 0xFB, 0xF8, 0xE3, 0x48, 0xEE, 0xF7, 0x64, 0xF9, 0x03, 0x28, + 0x10, 0xD0, 0x01, 0x28, + 0x11, 0xD0, 0x02, 0x28, 0x0F, 0xD0, 0xDF, 0x48, 0x00, 0x68, 0x01, 0x28, + 0x10, 0xD0, 0x12, 0xE0, + 0x00, 0x21, 0x24, 0x20, 0x01, 0xE0, 0x00, 0x21, 0x25, 0x20, 0xFF, 0xF7, + 0xDF, 0xFB, 0xE1, 0xE7, + 0x00, 0x21, 0x29, 0x20, 0x01, 0xE0, 0x00, 0x21, 0x2A, 0x20, 0xFF, 0xF7, + 0xD7, 0xFB, 0x02, 0xE0, + 0xD4, 0x48, 0xED, 0xF7, 0x7B, 0xFD, 0xD2, 0x48, 0x14, 0x30, 0xEE, 0xF7, + 0x6C, 0xF9, 0x04, 0x46, + 0x03, 0x28, 0x04, 0xD0, 0x01, 0x2C, 0x05, 0xD0, 0x02, 0x2C, 0x03, 0xD0, + 0x06, 0xE0, 0x00, 0x21, + 0x2B, 0x20, 0x01, 0xE0, 0x00, 0x21, 0x2C, 0x20, 0xFF, 0xF7, 0xC0, 0xFB, + 0x21, 0x46, 0xBD, 0xE8, + 0xF0, 0x41, 0xC7, 0x48, 0x14, 0x30, 0x00, 0xF0, 0x81, 0xBF, 0x7C, 0xB5, + 0xC6, 0x4E, 0x01, 0xAA, + 0x69, 0x46, 0x30, 0x46, 0xEE, 0xF7, 0x09, 0xFA, 0xC4, 0x4C, 0x40, 0xF2, + 0xBC, 0x65, 0x01, 0x28, + 0x02, 0xD0, 0x00, 0x21, 0x22, 0x20, 0x10, 0xE0, 0x00, 0x98, 0xA0, 0xF5, + 0x80, 0x71, 0xAF, 0x39, + 0xF7, 0xD1, 0x2A, 0x46, 0x31, 0x46, 0x20, 0x68, 0x04, 0xF0, 0x8F, 0xF9, + 0x20, 0x68, 0xEE, 0xF7, + 0x07, 0xFA, 0x01, 0x28, 0x08, 0xD0, 0x00, 0x21, 0x23, 0x20, 0xFF, 0xF7, + 0x97, 0xFB, 0x29, 0x46, + 0x20, 0x68, 0x04, 0xF0, 0x01, 0xFA, 0x7C, 0xBD, 0xB5, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x70, 0x11, + 0x89, 0x07, 0x07, 0xD4, 0x90, 0xF8, 0x88, 0x11, 0xC9, 0x06, 0x03, 0xD4, + 0x90, 0xF8, 0xA0, 0x01, + 0xC0, 0x06, 0xF0, 0xD5, 0x24, 0x68, 0x26, 0x22, 0x04, 0xF2, 0x02, 0x61, + 0xAD, 0x48, 0x04, 0xF0, + 0x6C, 0xF9, 0xAC, 0x48, 0x1D, 0x22, 0x04, 0xF5, 0xC5, 0x61, 0x28, 0x30, + 0x04, 0xF0, 0x65, 0xF9, + 0xA8, 0x48, 0x26, 0x22, 0x04, 0xF2, 0x5E, 0x61, 0x48, 0x30, 0x04, 0xF0, + 0x5E, 0xF9, 0xA5, 0x48, + 0x1D, 0x22, 0x04, 0xF2, 0x84, 0x61, 0x70, 0x30, 0x04, 0xF0, 0x57, 0xF9, + 0x7C, 0xBD, 0xF8, 0xB5, + 0x0D, 0x46, 0x06, 0x46, 0x00, 0x24, 0x6A, 0x46, 0xEE, 0xF7, 0xB7, 0xF9, + 0x01, 0x28, 0x01, 0xD0, + 0x01, 0x24, 0x0B, 0xE0, 0x28, 0x68, 0x31, 0x46, 0x82, 0x00, 0x9B, 0x48, + 0x04, 0xF0, 0x8A, 0xF9, + 0x99, 0x48, 0xEE, 0xF7, 0xBD, 0xF9, 0x01, 0x28, 0x00, 0xD0, 0x02, 0x24, + 0x20, 0x46, 0xF8, 0xBD, + 0x2D, 0xE9, 0xF8, 0x43, 0x94, 0x4D, 0x95, 0x4F, 0x10, 0x35, 0x41, 0xF2, + 0xC8, 0x11, 0x94, 0x48, + 0x04, 0xF0, 0xD4, 0xF9, 0x69, 0x46, 0x38, 0x46, 0xFF, 0xF7, 0xD9, 0xFF, + 0x01, 0x28, 0x05, 0xD0, + 0x02, 0x28, 0x06, 0xD0, 0xE8, 0x78, 0x01, 0x28, 0x0A, 0xD1, 0x05, 0xE0, + 0x00, 0x21, 0xA0, 0x20, + 0x2E, 0xE0, 0x00, 0x21, 0xA1, 0x20, 0x2B, 0xE0, 0xA8, 0x78, 0x08, 0xB9, + 0x28, 0x88, 0x10, 0xB1, + 0x00, 0x21, 0xA2, 0x20, 0x24, 0xE0, 0x82, 0x4E, 0xE9, 0x88, 0x30, 0x68, + 0x82, 0x8A, 0x91, 0x42, + 0x02, 0xD0, 0x00, 0x21, 0xA3, 0x20, 0x1B, 0xE0, 0xA9, 0x88, 0xC0, 0x8A, + 0x81, 0x42, 0x02, 0xD0, + 0x00, 0x21, 0xA4, 0x20, 0x14, 0xE0, 0x00, 0x24, 0x00, 0x98, 0x69, 0x46, + 0x07, 0xEB, 0x80, 0x07, + 0x38, 0x46, 0xFF, 0xF7, 0xAC, 0xFF, 0x78, 0xB1, 0x01, 0x28, 0x03, 0xD0, + 0x00, 0x21, 0xA6, 0x20, + 0xFF, 0xF7, 0x0C, 0xFB, 0xE0, 0x07, 0x35, 0xD0, 0xA0, 0x07, 0x35, 0xD4, + 0x11, 0x21, 0xA7, 0x20, + 0xFF, 0xF7, 0x04, 0xFB, 0xBD, 0xE8, 0xF8, 0x83, 0x95, 0xF8, 0x01, 0x80, + 0x29, 0x46, 0x40, 0x46, + 0x00, 0xF0, 0xDE, 0xFD, 0xA0, 0xB1, 0xB8, 0xF1, 0x10, 0x0F, 0x14, 0xD0, + 0xB8, 0xF1, 0x11, 0x0F, + 0x14, 0xD0, 0xB8, 0xF1, 0x12, 0x0F, 0x14, 0xD0, 0xB8, 0xF1, 0x13, 0x0F, + 0x14, 0xD0, 0xB8, 0xF1, + 0x14, 0x0F, 0x14, 0xD0, 0xB8, 0xF1, 0x17, 0x0F, 0xCE, 0xD1, 0x44, 0xF0, + 0x20, 0x04, 0xCB, 0xE7, + 0x41, 0x46, 0xA8, 0x20, 0xD4, 0xE7, 0x44, 0xF0, 0x01, 0x04, 0xC5, 0xE7, + 0x44, 0xF0, 0x02, 0x04, + 0xC2, 0xE7, 0x44, 0xF0, 0x08, 0x04, 0xBF, 0xE7, 0x44, 0xF0, 0x10, 0x04, + 0xBC, 0xE7, 0x44, 0xF0, + 0x04, 0x04, 0xB9, 0xE7, 0x10, 0x21, 0xCA, 0xE7, 0x20, 0x07, 0x0A, 0xD4, + 0x30, 0x68, 0x90, 0xF8, + 0x50, 0x12, 0xC9, 0x07, 0x03, 0xD1, 0x90, 0xF8, 0x80, 0x02, 0xC0, 0x07, + 0x01, 0xD0, 0x12, 0x21, + 0xBD, 0xE7, 0xE0, 0x06, 0x01, 0xD4, 0x13, 0x21, 0xB9, 0xE7, 0x60, 0x07, + 0x05, 0xD4, 0x30, 0x68, + 0x90, 0xF8, 0x61, 0x04, 0x08, 0xB1, 0x14, 0x21, 0xB1, 0xE7, 0xA0, 0x06, + 0xB2, 0xD4, 0x30, 0x68, + 0x90, 0xF8, 0x2F, 0x0A, 0xC0, 0x07, 0xAD, 0xD0, 0x17, 0x21, 0xA8, 0xE7, + 0x10, 0xB5, 0x8E, 0xB0, + 0xED, 0xF7, 0x66, 0xF9, 0x00, 0x20, 0x01, 0x22, 0x41, 0xB2, 0x01, 0xF0, + 0x1F, 0x03, 0x02, 0xFA, + 0x03, 0xF3, 0x49, 0x09, 0x89, 0x00, 0x01, 0xF1, 0xE0, 0x21, 0xC1, 0xF8, + 0x80, 0x31, 0x40, 0x1C, + 0x1F, 0x28, 0xF1, 0xDB, 0xED, 0xF7, 0x52, 0xF9, 0xED, 0xF7, 0x5C, 0xFF, + 0xEE, 0xF7, 0x26, 0xF9, + 0x07, 0x21, 0x0A, 0x20, 0xFF, 0xF7, 0x46, 0xFE, 0x07, 0x21, 0x0B, 0x20, + 0xFF, 0xF7, 0x42, 0xFE, + 0xFE, 0xF7, 0xFE, 0xFF, 0xFE, 0xF7, 0xAA, 0xFE, 0x04, 0xA8, 0xFF, 0xF7, + 0xEC, 0xF9, 0x0A, 0xA9, + 0x07, 0xA8, 0xFF, 0xF7, 0x89, 0xF8, 0x04, 0xA8, 0x00, 0x90, 0x07, 0xA8, + 0x02, 0x90, 0x0A, 0xA8, + 0x03, 0x90, 0x68, 0x46, 0xEE, 0xF7, 0x26, 0xFA, 0x02, 0x21, 0x00, 0x20, + 0xFF, 0xF7, 0x2A, 0xFE, + 0xFF, 0xF7, 0x04, 0xF8, 0xFF, 0xF7, 0x20, 0xFA, 0xFF, 0xF7, 0x40, 0xFE, + 0xED, 0xF7, 0x60, 0xFF, + 0x28, 0x4C, 0x01, 0xAA, 0x69, 0x46, 0x20, 0x46, 0xEE, 0xF7, 0xBF, 0xF8, + 0x01, 0x28, 0x02, 0xD0, + 0x00, 0x21, 0x20, 0x20, 0x11, 0xE0, 0x00, 0x98, 0xB0, 0xF5, 0x25, 0x7F, + 0xF8, 0xD1, 0x21, 0x46, + 0x1B, 0x4C, 0x4F, 0xF4, 0x25, 0x62, 0x20, 0x68, 0x04, 0xF0, 0x47, 0xF8, + 0x20, 0x68, 0xEE, 0xF7, + 0xBF, 0xF8, 0x01, 0x28, 0x03, 0xD0, 0x00, 0x21, 0x21, 0x20, 0xFF, 0xF7, + 0x02, 0xFA, 0xFF, 0xF7, + 0x94, 0xFE, 0xFF, 0xF7, 0xFD, 0xFE, 0x00, 0xF0, 0x07, 0xF8, 0x00, 0xF0, + 0x55, 0xF8, 0x0E, 0xB0, + 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, 0x86, 0xB8, 0x10, 0xB5, 0xEE, 0xF7, + 0xBF, 0xFA, 0x0B, 0x48, + 0x00, 0x68, 0x01, 0x7C, 0xA5, 0x29, 0x1F, 0xD0, 0x4F, 0xF4, 0xFA, 0x40, + 0xEE, 0xF7, 0x61, 0xFC, + 0x00, 0x21, 0x28, 0x20, 0xFF, 0xF7, 0x32, 0xFA, 0x19, 0xE0, 0x00, 0x00, + 0x00, 0x90, 0xD0, 0x03, + 0x84, 0x7B, 0x10, 0x00, 0xE8, 0x84, 0x10, 0x00, 0xF0, 0x9F, 0x01, 0x00, + 0x50, 0x07, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0xE4, 0x9F, 0x01, 0x20, 0xD4, 0x56, 0x10, 0x00, + 0xF0, 0xAF, 0x01, 0x00, + 0x78, 0x8B, 0x01, 0x20, 0xF0, 0xEF, 0x01, 0x00, 0x40, 0x69, 0xEE, 0xF7, + 0x42, 0xFC, 0x04, 0x21, + 0x02, 0x20, 0xFF, 0xF7, 0xC7, 0xFD, 0x04, 0x21, 0x03, 0x20, 0xFF, 0xF7, + 0xC3, 0xFD, 0x04, 0x21, + 0x08, 0x46, 0xFF, 0xF7, 0xBF, 0xFD, 0x04, 0x21, 0x05, 0x20, 0xFF, 0xF7, + 0xBB, 0xFD, 0x04, 0x21, + 0x06, 0x20, 0xFF, 0xF7, 0xB7, 0xFD, 0x04, 0x21, 0x07, 0x20, 0xFF, 0xF7, + 0xB3, 0xFD, 0x04, 0x21, + 0x08, 0x20, 0xFF, 0xF7, 0xAF, 0xFD, 0x01, 0x21, 0x09, 0x20, 0xFF, 0xF7, + 0xAB, 0xFD, 0x04, 0x21, + 0xBD, 0xE8, 0x10, 0x40, 0x0F, 0x20, 0xA5, 0xE5, 0x38, 0xB5, 0x03, 0xF0, + 0xFB, 0xFB, 0x03, 0x21, + 0x01, 0x20, 0xFF, 0xF7, 0x9F, 0xFD, 0x28, 0x4C, 0x20, 0x68, 0x90, 0xF8, + 0xB0, 0x10, 0xC9, 0x07, + 0x27, 0xD0, 0x00, 0x25, 0x00, 0x95, 0x90, 0xF8, 0xC0, 0x00, 0x2B, 0x46, + 0xC0, 0xF3, 0x02, 0x10, + 0x01, 0x22, 0x29, 0x46, 0xEE, 0xF7, 0x87, 0xF8, 0x20, 0x68, 0x0A, 0x21, + 0x90, 0xF8, 0xC0, 0x00, + 0xC0, 0xF3, 0x02, 0x10, 0xEE, 0xF7, 0xA7, 0xF8, 0x00, 0x95, 0x20, 0x68, + 0x00, 0x23, 0x01, 0x22, + 0x90, 0xF8, 0xC0, 0x00, 0x19, 0x46, 0x00, 0xF0, 0x07, 0x00, 0xEE, 0xF7, + 0x74, 0xF8, 0x20, 0x68, + 0x01, 0x21, 0x90, 0xF8, 0xC0, 0x00, 0xBD, 0xE8, 0x38, 0x40, 0x00, 0xF0, + 0x07, 0x00, 0xEE, 0xF7, + 0x92, 0xB8, 0x38, 0xBD, 0x38, 0xB5, 0x10, 0x4C, 0x20, 0x68, 0x90, 0xF8, + 0x60, 0x03, 0xC1, 0x07, + 0x0F, 0xD0, 0x81, 0x07, 0x0D, 0xD5, 0x00, 0x21, 0x01, 0x23, 0x40, 0x09, + 0x1A, 0x46, 0x00, 0x91, + 0xEE, 0xF7, 0x59, 0xF8, 0x20, 0x68, 0x00, 0x21, 0x90, 0xF8, 0x60, 0x03, + 0x40, 0x09, 0xEE, 0xF7, + 0x7A, 0xF8, 0x20, 0x68, 0x90, 0xF8, 0x79, 0x00, 0xBD, 0xE8, 0x38, 0x40, + 0x00, 0xF0, 0x03, 0x01, + 0xC0, 0x09, 0xED, 0xF7, 0xA5, 0xBE, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x88, 0x42, 0x00, 0xD3, + 0x08, 0x46, 0x90, 0x42, 0x00, 0xD3, 0x10, 0x46, 0x70, 0x47, 0x88, 0x42, + 0x00, 0xD8, 0x08, 0x46, + 0x90, 0x42, 0x00, 0xD8, 0x10, 0x46, 0x70, 0x47, 0x88, 0x42, 0x00, 0xD3, + 0x08, 0x46, 0x70, 0x47, + 0x88, 0x42, 0x00, 0xD8, 0x08, 0x46, 0x70, 0x47, 0x02, 0x46, 0x00, 0x20, + 0x4F, 0xF0, 0x80, 0x41, + 0x00, 0xE0, 0x89, 0x08, 0x91, 0x42, 0xFC, 0xD8, 0x07, 0xE0, 0x43, 0x18, + 0x93, 0x42, 0x02, 0xD8, + 0xD2, 0x1A, 0x00, 0xEB, 0x41, 0x00, 0x40, 0x08, 0x89, 0x08, 0x00, 0x29, + 0xF5, 0xD1, 0x82, 0x42, + 0x00, 0xD9, 0x40, 0x1C, 0x70, 0x47, 0x10, 0xB5, 0x5A, 0x43, 0x02, 0x9C, + 0x06, 0xE0, 0x00, 0xBF, + 0x50, 0xF8, 0x22, 0x30, 0x93, 0xFB, 0xF4, 0xF3, 0x41, 0xF8, 0x22, 0x30, + 0x52, 0x1E, 0xF7, 0xD2, + 0x10, 0xBD, 0x10, 0xB5, 0x5A, 0x43, 0x02, 0x9C, 0x05, 0xE0, 0x00, 0xBF, + 0x50, 0xF8, 0x22, 0x30, + 0x63, 0x43, 0x41, 0xF8, 0x22, 0x30, 0x52, 0x1E, 0xF8, 0xD2, 0x10, 0xBD, + 0x30, 0xB5, 0x03, 0x9C, + 0x63, 0x43, 0x06, 0xE0, 0x50, 0xF8, 0x23, 0x40, 0x51, 0xF8, 0x23, 0x50, + 0x2C, 0x44, 0x42, 0xF8, + 0x23, 0x40, 0x5B, 0x1E, 0xF6, 0xD2, 0x30, 0xBD, 0x30, 0xB5, 0x03, 0x9C, + 0x63, 0x43, 0x06, 0xE0, + 0x50, 0xF8, 0x23, 0x40, 0x51, 0xF8, 0x23, 0x50, 0x64, 0x1B, 0x42, 0xF8, + 0x23, 0x40, 0x5B, 0x1E, + 0xF6, 0xD2, 0x30, 0xBD, 0x2D, 0xE9, 0xF0, 0x4F, 0x83, 0x46, 0xDD, 0xE9, + 0x09, 0x06, 0xDD, 0xF8, + 0x34, 0xE0, 0x8A, 0x46, 0x82, 0x42, 0x26, 0xD1, 0x00, 0x20, 0x22, 0xE0, + 0x00, 0xFB, 0x02, 0xF1, + 0x0B, 0xEB, 0x81, 0x09, 0x0B, 0x9D, 0x00, 0xFB, 0x0E, 0xF1, 0x00, 0x24, + 0x05, 0xEB, 0x81, 0x05, + 0x14, 0xE0, 0x00, 0x21, 0x0F, 0xE0, 0x00, 0xBF, 0x01, 0xFB, 0x06, 0xF8, + 0x03, 0xEB, 0x88, 0x08, + 0x59, 0xF8, 0x21, 0xC0, 0x55, 0xF8, 0x24, 0x70, 0x58, 0xF8, 0x24, 0x80, + 0x49, 0x1C, 0x0C, 0xFB, + 0x08, 0x77, 0x45, 0xF8, 0x24, 0x70, 0x91, 0x42, 0xEE, 0xDB, 0x64, 0x1C, + 0xB4, 0x42, 0xE8, 0xDB, + 0x40, 0x1C, 0x50, 0x45, 0xDA, 0xDB, 0xBD, 0xE8, 0xF0, 0x8F, 0x10, 0xB5, + 0x00, 0x23, 0x1C, 0x46, + 0x42, 0xB1, 0x02, 0x78, 0x52, 0x1C, 0xD2, 0xB2, 0x02, 0x70, 0x8A, 0x42, + 0x03, 0xD9, 0x04, 0x70, + 0x01, 0x23, 0x00, 0xE0, 0x04, 0x70, 0x18, 0x46, 0x10, 0xBD, 0x30, 0xB5, + 0x00, 0x24, 0x01, 0x23, + 0x05, 0xE0, 0x0C, 0x44, 0xE4, 0x1C, 0x04, 0xF0, 0x03, 0x05, 0x64, 0x1B, + 0x5B, 0x1C, 0x93, 0x42, + 0xF7, 0xDD, 0x00, 0xEB, 0x44, 0x00, 0x30, 0xBD, 0x88, 0x42, 0x01, 0xDD, + 0x08, 0x46, 0x70, 0x47, + 0x00, 0x28, 0xFC, 0xDA, 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0x04, 0xE0, + 0x00, 0xEB, 0x82, 0x03, + 0x53, 0xF8, 0x04, 0x4C, 0x1C, 0x60, 0x52, 0x1E, 0xF8, 0xD1, 0x09, 0x68, + 0x01, 0x60, 0x10, 0xBD, + 0x10, 0xB5, 0x03, 0xE0, 0x00, 0xEB, 0x82, 0x03, 0x0C, 0x68, 0x1C, 0x60, + 0x52, 0x1E, 0xF9, 0xD2, + 0x10, 0xBD, 0x30, 0xB5, 0x06, 0xE0, 0x00, 0xBF, 0x00, 0xEB, 0xC2, 0x03, + 0x73, 0xE9, 0x02, 0x45, + 0xC3, 0xE9, 0x02, 0x45, 0x52, 0x1E, 0xF7, 0xD1, 0xD1, 0xE9, 0x00, 0x21, + 0xC0, 0xE9, 0x00, 0x21, + 0x30, 0xBD, 0x10, 0xB5, 0x53, 0x88, 0x4C, 0x88, 0x1B, 0x1B, 0x43, 0x80, + 0x12, 0x88, 0x09, 0x88, + 0x51, 0x1A, 0x01, 0x80, 0x10, 0xBD, 0x08, 0xB5, 0x0A, 0x46, 0x01, 0x46, + 0x68, 0x46, 0xFF, 0xF7, + 0xF0, 0xFF, 0xBD, 0xF9, 0x00, 0x10, 0xBD, 0xF9, 0x02, 0x00, 0x49, 0x43, + 0x00, 0xFB, 0x00, 0x10, + 0x08, 0xBD, 0x10, 0xB5, 0x88, 0x42, 0x02, 0x9C, 0x01, 0xDC, 0x20, 0x46, + 0x10, 0xBD, 0x90, 0x42, + 0x01, 0xDB, 0x18, 0x46, 0x10, 0xBD, 0x8A, 0x42, 0x00, 0xD1, 0x52, 0x1C, + 0x40, 0x1A, 0xE3, 0x1A, + 0x58, 0x43, 0x51, 0x1A, 0x90, 0xFB, 0xF1, 0xF0, 0x20, 0x1A, 0x10, 0xBD, + 0x10, 0xB5, 0x00, 0x2A, + 0x03, 0xD0, 0x43, 0x1A, 0x93, 0x42, 0x01, 0xDD, 0x88, 0x18, 0x10, 0xBD, + 0x54, 0x42, 0xA3, 0x42, + 0xFB, 0xDA, 0x88, 0x1A, 0x10, 0xBD, 0x91, 0x42, 0x01, 0xD1, 0x00, 0xB2, + 0x70, 0x47, 0x50, 0x43, + 0xB0, 0xFB, 0xF1, 0xF0, 0x00, 0xB2, 0x90, 0x42, 0xF7, 0xD9, 0x10, 0x46, + 0xF5, 0xE7, 0x70, 0xB5, + 0x0B, 0x00, 0x02, 0x46, 0x3D, 0xD0, 0x1F, 0x4C, 0x20, 0x68, 0x46, 0x8E, + 0x85, 0x8E, 0xB2, 0xF9, + 0x02, 0x00, 0x31, 0xB2, 0xFF, 0xF7, 0x80, 0xFF, 0x58, 0x80, 0xB2, 0xF9, + 0x00, 0x00, 0x29, 0xB2, + 0xFF, 0xF7, 0x7A, 0xFF, 0x18, 0x80, 0x21, 0x68, 0x91, 0xF8, 0x36, 0x10, + 0x49, 0x07, 0x02, 0xD5, + 0x59, 0x88, 0x71, 0x1A, 0x59, 0x80, 0x21, 0x68, 0x91, 0xF8, 0x36, 0x10, + 0x89, 0x07, 0x01, 0xD5, + 0x28, 0x1A, 0x18, 0x80, 0x20, 0x68, 0x90, 0xF8, 0x36, 0x10, 0x09, 0x07, + 0x10, 0xD5, 0xB0, 0xF8, + 0x37, 0x20, 0xB3, 0xF9, 0x02, 0x00, 0x31, 0x46, 0xFF, 0xF7, 0xC5, 0xFF, + 0x58, 0x80, 0x20, 0x68, + 0x29, 0x46, 0xB0, 0xF8, 0x39, 0x20, 0xB3, 0xF9, 0x00, 0x00, 0xFF, 0xF7, + 0xBC, 0xFF, 0x18, 0x80, + 0x20, 0x68, 0x90, 0xF8, 0x36, 0x00, 0xC0, 0x07, 0x03, 0xD0, 0x58, 0x88, + 0x19, 0x88, 0x59, 0x80, + 0x18, 0x80, 0x70, 0xBD, 0x4C, 0x07, 0x10, 0x00, 0x31, 0xB5, 0xED, 0xF7, + 0xE1, 0xF9, 0x04, 0x00, + 0x08, 0xD4, 0xDD, 0xF8, 0x00, 0x00, 0x01, 0x22, 0x02, 0xFA, 0x04, 0xF1, + 0x01, 0x42, 0x01, 0xD1, + 0x64, 0x1E, 0xF9, 0xD5, 0x04, 0x21, 0x68, 0x46, 0xED, 0xF7, 0x5D, 0xFE, + 0xFE, 0x49, 0xC0, 0xB2, + 0x09, 0x68, 0x91, 0xF8, 0xE7, 0x10, 0xC1, 0xF3, 0x41, 0x11, 0x02, 0x29, + 0x0E, 0xD3, 0x10, 0xF0, + 0x03, 0x00, 0x05, 0xD0, 0x01, 0x28, 0x05, 0xD0, 0x02, 0x28, 0x05, 0xD0, + 0x1F, 0x20, 0x0A, 0xE0, + 0x0F, 0x20, 0x08, 0xE0, 0x7F, 0x20, 0x06, 0xE0, 0x3F, 0x20, 0x04, 0xE0, + 0xC0, 0x07, 0x01, 0xD0, + 0x07, 0x20, 0x00, 0xE0, 0x03, 0x20, 0x64, 0x1C, 0x00, 0x99, 0xA0, 0x40, + 0x08, 0x43, 0x38, 0xBD, + 0x10, 0xB5, 0xEE, 0x4C, 0x50, 0x28, 0x13, 0xD0, 0x09, 0xDC, 0xA0, 0xF1, + 0x10, 0x00, 0x08, 0x28, + 0x40, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x0D, 0x20, 0x20, 0x20, 0x26, 0x3F, + 0x3F, 0x39, 0x51, 0x38, + 0x07, 0x28, 0x37, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x17, 0x17, 0x17, 0x1D, + 0x36, 0x36, 0x30, 0x00, + 0x03, 0xF0, 0x8D, 0xFA, 0x20, 0x60, 0x03, 0xF0, 0x8C, 0xFA, 0xC4, 0xE9, + 0x04, 0x01, 0xDE, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0xE7, 0x00, 0x10, 0xF0, 0x60, 0x0F, 0x11, 0xD0, + 0x20, 0x68, 0xFF, 0xF7, + 0xA3, 0xFF, 0x20, 0x60, 0x0C, 0xE0, 0x03, 0xF0, 0x7A, 0xFA, 0x20, 0x60, + 0x03, 0xF0, 0x79, 0xFA, + 0x04, 0xE0, 0x03, 0xF0, 0x78, 0xFA, 0x20, 0x60, 0x03, 0xF0, 0x77, 0xFA, + 0xC4, 0xE9, 0x04, 0x01, + 0x04, 0x21, 0xD2, 0x48, 0xED, 0xF7, 0xFF, 0xFD, 0x60, 0x60, 0xD0, 0x48, + 0x08, 0x21, 0x10, 0x30, + 0xED, 0xF7, 0xF9, 0xFD, 0xA0, 0x60, 0x10, 0xBD, 0x03, 0xF0, 0x69, 0xFA, + 0x20, 0x60, 0x03, 0xF0, + 0x68, 0xFA, 0xEB, 0xE7, 0x00, 0x20, 0x01, 0x46, 0x20, 0x60, 0xE7, 0xE7, + 0x2D, 0xE9, 0xFF, 0x5F, + 0x04, 0x21, 0xDD, 0xE9, 0x0F, 0xAB, 0x68, 0x46, 0xED, 0xF7, 0xE5, 0xFD, + 0x81, 0x46, 0x08, 0x21, + 0x02, 0xA8, 0xED, 0xF7, 0xE0, 0xFD, 0x07, 0x46, 0x00, 0x24, 0x20, 0x46, + 0x35, 0xE0, 0x01, 0x20, + 0x00, 0x99, 0x00, 0xFA, 0x08, 0xF0, 0x08, 0x42, 0x2D, 0xD0, 0x00, 0x25, + 0x2E, 0x46, 0x27, 0xE0, + 0x32, 0x46, 0x01, 0x20, 0x00, 0x21, 0x03, 0xF0, 0x41, 0xFD, 0xDD, 0xE9, + 0x02, 0x23, 0x10, 0x40, + 0x19, 0x40, 0x08, 0x43, 0x1B, 0xD0, 0x11, 0x98, 0x60, 0xB1, 0x04, 0xFB, + 0x07, 0xF0, 0x0A, 0xEB, + 0x05, 0x01, 0x41, 0x56, 0x32, 0x46, 0x01, 0xEB, 0x0B, 0x03, 0x21, 0x46, + 0x0E, 0x98, 0xED, 0xF7, + 0xBC, 0xF9, 0x0B, 0xE0, 0x32, 0x46, 0x21, 0x46, 0x0E, 0x98, 0xED, 0xF7, + 0xAB, 0xF9, 0x04, 0xFB, + 0x07, 0xF1, 0x0A, 0xEB, 0x05, 0x02, 0xA0, 0xEB, 0x0B, 0x00, 0x88, 0x54, + 0x6D, 0x1C, 0x76, 0x1C, + 0xBD, 0x42, 0xD5, 0xDB, 0x64, 0x1C, 0x08, 0xF1, 0x01, 0x00, 0x80, 0x46, + 0x4C, 0x45, 0xC6, 0xDB, + 0xBD, 0xE8, 0xFF, 0x9F, 0x2D, 0xE9, 0xFF, 0x5F, 0x84, 0xB0, 0x04, 0x21, + 0xDD, 0xE9, 0x12, 0xAB, + 0x04, 0xA8, 0xED, 0xF7, 0x98, 0xFD, 0x81, 0x46, 0x08, 0x21, 0x06, 0xA8, + 0xED, 0xF7, 0x93, 0xFD, + 0x07, 0x46, 0x00, 0x25, 0x0A, 0xF1, 0x48, 0x00, 0x02, 0x90, 0x20, 0x30, + 0x01, 0x90, 0x48, 0x38, + 0x2C, 0x46, 0xA8, 0x46, 0x2E, 0x46, 0x00, 0x90, 0x31, 0xE0, 0x01, 0x20, + 0x04, 0x99, 0x00, 0xFA, + 0x08, 0xF0, 0x08, 0x42, 0x27, 0xD0, 0x16, 0x98, 0x90, 0xB1, 0x1B, 0xF8, + 0x05, 0x10, 0x14, 0x98, + 0x08, 0x44, 0xC2, 0xB2, 0x41, 0x46, 0x02, 0x98, 0xED, 0xF7, 0xDF, 0xF9, + 0x05, 0xEB, 0x09, 0x00, + 0xC1, 0x19, 0x1B, 0xF9, 0x01, 0x20, 0x41, 0x46, 0x50, 0x46, 0xED, 0xF7, + 0xAD, 0xF9, 0x10, 0xE0, + 0x41, 0x46, 0x02, 0x98, 0xED, 0xF7, 0xCF, 0xF9, 0x14, 0x99, 0x40, 0x1A, + 0x0B, 0xF8, 0x05, 0x00, + 0x41, 0x46, 0x50, 0x46, 0xED, 0xF7, 0x99, 0xF9, 0x05, 0xEB, 0x09, 0x01, + 0xCA, 0x19, 0x0B, 0xF8, + 0x02, 0x00, 0x6D, 0x1C, 0xED, 0xB2, 0x08, 0xF1, 0x01, 0x00, 0x00, 0xF0, + 0xFF, 0x08, 0x4D, 0x45, + 0xCB, 0xDB, 0x38, 0xE0, 0x32, 0x46, 0x01, 0x20, 0x00, 0x21, 0x03, 0xF0, + 0xBF, 0xFC, 0xDD, 0xE9, + 0x06, 0x23, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x2B, 0xD0, 0x16, 0x98, + 0xA0, 0xB1, 0x04, 0xEB, + 0x09, 0x01, 0x15, 0x98, 0x1B, 0xF8, 0x01, 0x10, 0x08, 0x44, 0xC2, 0xB2, + 0x31, 0x46, 0x01, 0x98, + 0xED, 0xF7, 0xA3, 0xF9, 0x04, 0xEB, 0x49, 0x00, 0xC1, 0x19, 0x1B, 0xF9, + 0x01, 0x20, 0x31, 0x46, + 0x00, 0x98, 0xED, 0xF7, 0x71, 0xF9, 0x12, 0xE0, 0x31, 0x46, 0x01, 0x98, + 0xED, 0xF7, 0x93, 0xF9, + 0x15, 0x99, 0x04, 0xEB, 0x09, 0x02, 0x40, 0x1A, 0x0B, 0xF8, 0x02, 0x00, + 0x31, 0x46, 0x00, 0x98, + 0xED, 0xF7, 0x5B, 0xF9, 0x04, 0xEB, 0x49, 0x01, 0xCA, 0x19, 0x0B, 0xF8, + 0x02, 0x00, 0x64, 0x1C, + 0xE4, 0xB2, 0x76, 0x1C, 0xF6, 0xB2, 0xBC, 0x42, 0xC4, 0xDB, 0x08, 0xB0, + 0xBD, 0xE8, 0xF0, 0x9F, + 0x2D, 0xE9, 0xFF, 0x5F, 0x04, 0x21, 0xDD, 0xE9, 0x0E, 0xBA, 0x68, 0x46, + 0xED, 0xF7, 0x0B, 0xFD, + 0x81, 0x46, 0x08, 0x21, 0x02, 0xA8, 0xED, 0xF7, 0x06, 0xFD, 0x07, 0x46, + 0x00, 0x24, 0x20, 0x46, + 0x24, 0xE0, 0x01, 0x20, 0x00, 0x99, 0x00, 0xFA, 0x08, 0xF0, 0x08, 0x42, + 0x1C, 0xD0, 0x00, 0x25, + 0x2E, 0x46, 0x16, 0xE0, 0x32, 0x46, 0x01, 0x20, 0x00, 0x21, 0x03, 0xF0, + 0x67, 0xFC, 0xDD, 0xE9, + 0x02, 0x23, 0x10, 0x40, 0x19, 0x40, 0x08, 0x43, 0x0A, 0xD0, 0x32, 0x46, + 0x21, 0x46, 0x58, 0x46, + 0xED, 0xF7, 0xE0, 0xF8, 0x04, 0xFB, 0x07, 0x52, 0x80, 0x00, 0x2A, 0xF8, + 0x12, 0x00, 0x6D, 0x1C, + 0x76, 0x1C, 0xBD, 0x42, 0xE6, 0xDB, 0x64, 0x1C, 0x08, 0xF1, 0x01, 0x00, + 0x80, 0x46, 0x4C, 0x45, + 0xD7, 0xDB, 0x35, 0xE7, 0x2D, 0xE9, 0xFF, 0x5F, 0x04, 0x21, 0xDD, 0xE9, + 0x0E, 0x9B, 0x68, 0x46, + 0xED, 0xF7, 0xD1, 0xFC, 0x82, 0x46, 0x08, 0x21, 0x02, 0xA8, 0xED, 0xF7, + 0xCC, 0xFC, 0x00, 0x25, + 0x80, 0x46, 0x2C, 0x46, 0x2F, 0x46, 0x2E, 0x46, 0x36, 0xE0, 0x01, 0x20, + 0x00, 0x99, 0xB8, 0x40, + 0x08, 0x42, 0x2F, 0xD0, 0x39, 0x46, 0x09, 0xF1, 0x48, 0x00, 0xED, 0xF7, + 0x24, 0xF9, 0x2E, 0x49, + 0x99, 0xF8, 0x92, 0x30, 0x09, 0x68, 0x91, 0xF8, 0x43, 0xC1, 0x91, 0xF8, + 0x42, 0x11, 0x0C, 0xF0, + 0x0F, 0x02, 0x52, 0x1C, 0x53, 0x43, 0x01, 0x22, 0x02, 0xEB, 0x1C, 0x1C, + 0x00, 0xFB, 0x0C, 0x33, + 0x99, 0xF8, 0x90, 0x00, 0x02, 0xEB, 0x11, 0x11, 0x00, 0xFB, 0x01, 0x30, + 0x10, 0x99, 0x19, 0xB9, + 0x4F, 0xF6, 0xFF, 0x71, 0x01, 0xEA, 0x80, 0x00, 0x2B, 0xF8, 0x15, 0x00, + 0x39, 0x46, 0x48, 0x46, + 0xED, 0xF7, 0xD3, 0xF8, 0x05, 0xEB, 0x0A, 0x02, 0x80, 0x00, 0x42, 0x44, + 0x6D, 0x1C, 0x2B, 0xF8, + 0x12, 0x00, 0xED, 0xB2, 0x7F, 0x1C, 0xFF, 0xB2, 0x55, 0x45, 0xC6, 0xDB, + 0x45, 0xE0, 0x32, 0x46, + 0x01, 0x20, 0x00, 0x21, 0x03, 0xF0, 0xFA, 0xFB, 0xDD, 0xE9, 0x02, 0x23, + 0x10, 0x40, 0x19, 0x40, + 0x08, 0x43, 0x38, 0xD0, 0x31, 0x46, 0x09, 0xF1, 0x68, 0x00, 0xED, 0xF7, + 0xE4, 0xF8, 0x0E, 0x49, + 0x99, 0xF8, 0x93, 0x50, 0x09, 0x68, 0x91, 0xF8, 0x48, 0x21, 0x91, 0xF8, + 0x47, 0x11, 0x02, 0xF0, + 0x0F, 0x03, 0x5B, 0x1C, 0x5D, 0x43, 0x01, 0x23, 0x03, 0xEB, 0x12, 0x12, + 0x00, 0xFB, 0x02, 0x52, + 0x99, 0xF8, 0x91, 0x00, 0x03, 0xEB, 0x11, 0x11, 0x00, 0xFB, 0x01, 0x20, + 0x10, 0x99, 0x49, 0xB9, + 0x4F, 0xF6, 0xFF, 0x71, 0x04, 0xE0, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0xB0, 0x07, 0x10, 0x00, + 0x01, 0xEA, 0x80, 0x00, 0x04, 0xEB, 0x0A, 0x02, 0x31, 0x46, 0x2B, 0xF8, + 0x12, 0x00, 0x09, 0xF1, + 0x20, 0x00, 0xED, 0xF7, 0x8A, 0xF8, 0x04, 0xEB, 0x4A, 0x02, 0x80, 0x00, + 0x42, 0x44, 0x64, 0x1C, + 0x2B, 0xF8, 0x12, 0x00, 0xE4, 0xB2, 0x76, 0x1C, 0xF6, 0xB2, 0x44, 0x45, + 0xB7, 0xDB, 0x9F, 0xE6, + 0x2D, 0xE9, 0xF0, 0x43, 0x89, 0x46, 0x00, 0x27, 0x85, 0xB0, 0x90, 0x46, + 0x04, 0x46, 0x3E, 0x46, + 0xFC, 0x21, 0x03, 0xF0, 0x61, 0xFC, 0xFE, 0x4D, 0xB8, 0xF1, 0x01, 0x0F, + 0x28, 0x79, 0x20, 0x71, + 0x28, 0x7A, 0x60, 0x71, 0xFB, 0x48, 0x90, 0xF8, 0x52, 0x1E, 0xA1, 0x71, + 0x90, 0xF8, 0x53, 0x1E, + 0xE1, 0x71, 0x90, 0xF8, 0x54, 0x1E, 0xA1, 0x72, 0x90, 0xF8, 0x55, 0x1E, + 0xE1, 0x72, 0x90, 0xF8, + 0x50, 0x1E, 0x21, 0x73, 0x90, 0xF8, 0x51, 0x0E, 0x60, 0x73, 0x08, 0xD1, + 0xF2, 0x48, 0x00, 0x68, + 0x81, 0x7F, 0xA5, 0x29, 0x03, 0xD1, 0x90, 0xF9, 0x1F, 0x70, 0x90, 0xF9, + 0x20, 0x60, 0x04, 0xF1, + 0x10, 0x00, 0xCD, 0xE9, 0x01, 0x07, 0xED, 0x48, 0x00, 0x21, 0x00, 0x90, + 0xCD, 0xE9, 0x03, 0x61, + 0xD5, 0xE9, 0x04, 0x23, 0x28, 0x68, 0xFF, 0xF7, 0x65, 0xFE, 0xA5, 0x20, + 0x20, 0x70, 0x12, 0x20, + 0x60, 0x70, 0xA4, 0xF8, 0x02, 0x90, 0xD5, 0xE9, 0x01, 0x01, 0x08, 0x44, + 0x13, 0x30, 0x80, 0x08, + 0x05, 0xB0, 0xBD, 0xE8, 0xF0, 0x83, 0x2D, 0xE9, 0xF0, 0x43, 0x89, 0x46, + 0x00, 0x27, 0x85, 0xB0, + 0x90, 0x46, 0x04, 0x46, 0x3E, 0x46, 0xFC, 0x21, 0x03, 0xF0, 0x16, 0xFC, + 0xD8, 0x4D, 0xB8, 0xF1, + 0x01, 0x0F, 0x28, 0x79, 0x20, 0x71, 0x28, 0x7A, 0x60, 0x71, 0xD6, 0x48, + 0x90, 0xF8, 0xEA, 0x1E, + 0xA1, 0x71, 0x90, 0xF8, 0xEB, 0x1E, 0xE1, 0x71, 0x90, 0xF8, 0xEC, 0x1E, + 0xA1, 0x72, 0x90, 0xF8, + 0xED, 0x1E, 0xE1, 0x72, 0x90, 0xF8, 0xE8, 0x1E, 0x21, 0x73, 0x90, 0xF8, + 0xE9, 0x0E, 0x60, 0x73, + 0x09, 0xD1, 0xCD, 0x48, 0x00, 0x68, 0x90, 0xF8, 0x21, 0x10, 0xA5, 0x29, + 0x03, 0xD1, 0x10, 0xF9, + 0x22, 0x7F, 0x90, 0xF9, 0x01, 0x60, 0x04, 0xF1, 0x10, 0x00, 0xCD, 0xE9, + 0x01, 0x07, 0xC7, 0x48, + 0x00, 0x21, 0x98, 0x30, 0x00, 0x90, 0xCD, 0xE9, 0x03, 0x61, 0xD5, 0xE9, + 0x04, 0x23, 0x28, 0x68, + 0xFF, 0xF7, 0x18, 0xFE, 0xA5, 0x20, 0x20, 0x70, 0x13, 0x20, 0x60, 0x70, + 0xA4, 0xF8, 0x02, 0x90, + 0xD5, 0xE9, 0x01, 0x01, 0x08, 0x44, 0x13, 0x30, 0x80, 0x08, 0xB1, 0xE7, + 0x2D, 0xE9, 0xF0, 0x43, + 0x89, 0x46, 0x00, 0x27, 0x85, 0xB0, 0x90, 0x46, 0x04, 0x46, 0x3E, 0x46, + 0xFC, 0x21, 0x03, 0xF0, + 0xCB, 0xFB, 0xB3, 0x4D, 0xB8, 0xF1, 0x01, 0x0F, 0x28, 0x79, 0x20, 0x71, + 0x28, 0x7A, 0x60, 0x71, + 0xB0, 0x48, 0x90, 0xF8, 0x82, 0x1F, 0xA1, 0x71, 0x90, 0xF8, 0x83, 0x1F, + 0xE1, 0x71, 0x90, 0xF8, + 0x84, 0x1F, 0xA1, 0x72, 0x90, 0xF8, 0x85, 0x1F, 0xE1, 0x72, 0x90, 0xF8, + 0x80, 0x1F, 0x21, 0x73, + 0x90, 0xF8, 0x81, 0x0F, 0x60, 0x73, 0x09, 0xD1, 0xA7, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x26, 0x10, + 0xA5, 0x29, 0x03, 0xD1, 0x10, 0xF9, 0x27, 0x7F, 0x90, 0xF9, 0x01, 0x60, + 0x04, 0xF1, 0x10, 0x00, + 0xCD, 0xE9, 0x01, 0x07, 0xA2, 0x48, 0x00, 0x21, 0x00, 0x90, 0xCD, 0xE9, + 0x03, 0x61, 0xD5, 0xE9, + 0x04, 0x23, 0x28, 0x68, 0xFF, 0xF7, 0xCE, 0xFD, 0xA5, 0x20, 0x20, 0x70, + 0x17, 0x20, 0x60, 0x70, + 0xA4, 0xF8, 0x02, 0x90, 0xD5, 0xE9, 0x01, 0x01, 0x08, 0x44, 0x13, 0x30, + 0x80, 0x08, 0x67, 0xE7, + 0x2D, 0xE9, 0xFF, 0x41, 0x0D, 0x46, 0x07, 0x46, 0x00, 0x26, 0xFF, 0xF7, + 0x21, 0xFD, 0x01, 0x22, + 0x8F, 0x4C, 0x91, 0x49, 0x10, 0x3F, 0x05, 0xF1, 0x10, 0x00, 0x08, 0x2F, + 0x4E, 0xD2, 0xDF, 0xE8, + 0x07, 0xF0, 0x04, 0x15, 0x26, 0x2A, 0x2F, 0x4D, 0x4D, 0x51, 0x2B, 0x79, + 0x66, 0x68, 0xB3, 0x42, + 0x2E, 0xD1, 0x6B, 0x79, 0xA5, 0x68, 0xAB, 0x42, 0x2A, 0xD1, 0x09, 0x68, + 0x00, 0x23, 0x8D, 0x7E, + 0xA5, 0x2D, 0x01, 0xD1, 0x91, 0xF9, 0x1B, 0x30, 0x82, 0x49, 0x2D, 0xE0, + 0x2B, 0x79, 0x66, 0x68, + 0xB3, 0x42, 0x1D, 0xD1, 0x6B, 0x79, 0xA5, 0x68, 0xAB, 0x42, 0x19, 0xD1, + 0x09, 0x68, 0x00, 0x23, + 0x0D, 0x7F, 0xA5, 0x2D, 0x01, 0xD1, 0x91, 0xF9, 0x1D, 0x30, 0x7E, 0x49, + 0x1C, 0xE0, 0x28, 0x46, + 0x00, 0xF0, 0x12, 0xF9, 0x02, 0xE0, 0x28, 0x46, 0x00, 0xF0, 0x49, 0xF9, + 0x06, 0x46, 0x1D, 0xE0, + 0x2B, 0x79, 0x66, 0x68, 0xB3, 0x42, 0x03, 0xD1, 0x6B, 0x79, 0xA5, 0x68, + 0xAB, 0x42, 0x01, 0xD0, + 0x00, 0x26, 0x13, 0xE0, 0x09, 0x68, 0x00, 0x23, 0x91, 0xF8, 0x24, 0x50, + 0xA5, 0x2D, 0x01, 0xD1, + 0x91, 0xF9, 0x25, 0x30, 0x6D, 0x49, 0xA0, 0x39, 0xCD, 0xE9, 0x00, 0x10, + 0xCD, 0xE9, 0x02, 0x32, + 0xD4, 0xE9, 0x04, 0x23, 0x20, 0x68, 0xFF, 0xF7, 0x19, 0xFD, 0x01, 0x26, + 0x30, 0x46, 0x04, 0xB0, + 0xBD, 0xE8, 0xF0, 0x81, 0x28, 0x46, 0x00, 0xF0, 0x5E, 0xF9, 0xD7, 0xE7, + 0x2D, 0xE9, 0xF0, 0x41, + 0x1E, 0x46, 0x17, 0x46, 0x88, 0x46, 0x05, 0x46, 0x00, 0x24, 0xFF, 0xF7, + 0xB9, 0xFC, 0x10, 0x3D, + 0x08, 0x2D, 0x11, 0xD2, 0xDF, 0xE8, 0x05, 0xF0, 0x04, 0x0A, 0x12, 0x18, + 0x1E, 0x10, 0x10, 0x24, + 0x32, 0x46, 0x39, 0x46, 0x40, 0x46, 0x00, 0xF0, 0x81, 0xF9, 0x04, 0xE0, + 0x32, 0x46, 0x39, 0x46, + 0x40, 0x46, 0x00, 0xF0, 0xAC, 0xF9, 0x04, 0x46, 0x20, 0x46, 0xD9, 0xE7, + 0x32, 0x46, 0x39, 0x46, + 0x40, 0x46, 0xFF, 0xF7, 0x95, 0xFE, 0xF6, 0xE7, 0x32, 0x46, 0x39, 0x46, + 0x40, 0x46, 0xFF, 0xF7, + 0xDA, 0xFE, 0xF0, 0xE7, 0x32, 0x46, 0x39, 0x46, 0x40, 0x46, 0x00, 0xF0, + 0xC9, 0xF9, 0xEA, 0xE7, + 0x32, 0x46, 0x39, 0x46, 0x40, 0x46, 0xFF, 0xF7, 0x19, 0xFF, 0xE4, 0xE7, + 0xFE, 0xB5, 0x17, 0x46, + 0x06, 0x46, 0x0D, 0x46, 0xFF, 0xF7, 0x84, 0xFC, 0x41, 0x48, 0x47, 0x4A, + 0x05, 0xF1, 0x10, 0x04, + 0x01, 0x79, 0x29, 0x71, 0x01, 0x7A, 0x69, 0x71, 0xA6, 0xF1, 0x50, 0x01, + 0x08, 0x29, 0x26, 0xD2, + 0xDF, 0xE8, 0x01, 0xF0, 0x04, 0x06, 0x0F, 0x16, 0x2A, 0x25, 0x25, 0x2D, + 0x39, 0x49, 0x00, 0xE0, + 0x3C, 0x49, 0xCD, 0xE9, 0x00, 0x14, 0xD0, 0xE9, 0x04, 0x23, 0x00, 0x68, + 0xFF, 0xF7, 0x90, 0xFD, + 0x15, 0xE0, 0x11, 0x68, 0x35, 0x4A, 0x91, 0xF8, 0x42, 0x11, 0x01, 0xF0, + 0x01, 0x01, 0x06, 0xE0, + 0x11, 0x68, 0x32, 0x4A, 0x91, 0xF8, 0x92, 0x19, 0x98, 0x32, 0x01, 0xF0, + 0x01, 0x01, 0x00, 0x92, + 0xCD, 0xE9, 0x01, 0x41, 0xD0, 0xE9, 0x04, 0x23, 0x00, 0x68, 0xFF, 0xF7, + 0xB3, 0xFD, 0xA5, 0x20, + 0x28, 0x70, 0x6E, 0x70, 0x6F, 0x80, 0xFE, 0xBD, 0x28, 0x49, 0xA0, 0x39, + 0xD9, 0xE7, 0x11, 0x68, + 0x27, 0x4A, 0x91, 0xF8, 0x12, 0x1A, 0x01, 0xF0, 0x01, 0x01, 0xE8, 0xE7, + 0x2D, 0xE9, 0xF0, 0x41, + 0x0C, 0x46, 0x05, 0x46, 0x4F, 0xF4, 0x29, 0x71, 0x24, 0x48, 0x03, 0xF0, + 0xBF, 0xFA, 0x23, 0x48, + 0x00, 0x2C, 0x04, 0x60, 0x57, 0xD1, 0x80, 0x46, 0x04, 0xEB, 0x84, 0x00, + 0xC4, 0xEB, 0xC4, 0x01, + 0x05, 0xEB, 0xC0, 0x06, 0x08, 0xEB, 0x01, 0x17, 0x38, 0x1D, 0x28, 0x22, + 0x31, 0x46, 0x03, 0xF0, + 0x0C, 0xFA, 0xC4, 0xEB, 0x04, 0x10, 0x05, 0xEB, 0x80, 0x01, 0x07, 0xF1, + 0x2C, 0x00, 0x20, 0x22, + 0x78, 0x31, 0x03, 0xF0, 0x02, 0xFA, 0x06, 0xF5, 0x96, 0x71, 0x07, 0xF1, + 0x4C, 0x00, 0x28, 0x22, + 0x03, 0xF0, 0xFB, 0xF9, 0x64, 0x1C, 0x03, 0x2C, 0xDE, 0xDB, 0x00, 0x24, + 0x04, 0xEB, 0x84, 0x00, + 0xC4, 0xEB, 0xC4, 0x02, 0x05, 0xEB, 0xC0, 0x06, 0x08, 0xEB, 0x02, 0x17, + 0x06, 0xF5, 0xD2, 0x71, + 0x07, 0xF5, 0xAA, 0x70, 0x28, 0x22, 0x03, 0xF0, 0xE8, 0xF9, 0xC4, 0xEB, + 0x04, 0x10, 0x0F, 0xE0, + 0xB0, 0x07, 0x10, 0x00, 0x78, 0x8B, 0x01, 0x20, 0x50, 0x07, 0x10, 0x00, + 0x38, 0x99, 0x01, 0x20, + 0x68, 0x9A, 0x01, 0x20, 0x08, 0x92, 0x01, 0x20, 0x4C, 0x07, 0x10, 0x00, + 0x40, 0x9D, 0x01, 0x20, + 0x05, 0xEB, 0x80, 0x01, 0x07, 0xF5, 0xBE, 0x70, 0x20, 0x22, 0x01, 0xF5, + 0x07, 0x71, 0x03, 0xF0, + 0xCC, 0xF9, 0x06, 0xF5, 0x34, 0x71, 0x07, 0xF5, 0xCE, 0x70, 0x28, 0x22, + 0x03, 0xF0, 0xC5, 0xF9, + 0x64, 0x1C, 0x03, 0x2C, 0xCA, 0xDB, 0x13, 0xE7, 0x30, 0xB5, 0xA3, 0x49, + 0x02, 0x79, 0x85, 0xB0, + 0x4B, 0x68, 0x9A, 0x42, 0x03, 0xD1, 0x42, 0x79, 0x8B, 0x68, 0x9A, 0x42, + 0x02, 0xD0, 0x00, 0x20, + 0x05, 0xB0, 0x30, 0xBD, 0x9D, 0x4A, 0x85, 0x79, 0x00, 0x24, 0x82, 0xF8, + 0x52, 0x5E, 0xC5, 0x79, + 0x82, 0xF8, 0x53, 0x5E, 0x85, 0x7A, 0x82, 0xF8, 0x54, 0x5E, 0xC5, 0x7A, + 0x82, 0xF8, 0x55, 0x5E, + 0x05, 0x7B, 0x82, 0xF8, 0x50, 0x5E, 0x45, 0x7B, 0x82, 0xF8, 0x51, 0x5E, + 0x94, 0x4A, 0x23, 0x46, + 0x12, 0x68, 0x95, 0x7F, 0xA5, 0x2D, 0x03, 0xD1, 0x92, 0xF9, 0x1F, 0x40, + 0x92, 0xF9, 0x20, 0x30, + 0x10, 0x30, 0xCD, 0xE9, 0x01, 0x04, 0x8F, 0x48, 0x01, 0x22, 0x00, 0x90, + 0xCD, 0xE9, 0x03, 0x32, + 0xD1, 0xE9, 0x04, 0x23, 0x08, 0x68, 0xFF, 0xF7, 0x3D, 0xFC, 0x01, 0x20, + 0xD0, 0xE7, 0x30, 0xB5, + 0x85, 0x49, 0x02, 0x79, 0x85, 0xB0, 0x4B, 0x68, 0x9A, 0x42, 0x03, 0xD1, + 0x42, 0x79, 0x8B, 0x68, + 0x9A, 0x42, 0x01, 0xD0, 0x00, 0x20, 0xC3, 0xE7, 0x80, 0x4A, 0x85, 0x79, + 0x00, 0x24, 0x82, 0xF8, + 0xEA, 0x5E, 0xC5, 0x79, 0x82, 0xF8, 0xEB, 0x5E, 0x85, 0x7A, 0x82, 0xF8, + 0xEC, 0x5E, 0xC5, 0x7A, + 0x82, 0xF8, 0xED, 0x5E, 0x05, 0x7B, 0x82, 0xF8, 0xE8, 0x5E, 0x45, 0x7B, + 0x82, 0xF8, 0xE9, 0x5E, + 0x77, 0x4A, 0x23, 0x46, 0x12, 0x68, 0x92, 0xF8, 0x21, 0x50, 0xA5, 0x2D, + 0x03, 0xD1, 0x12, 0xF9, + 0x22, 0x4F, 0x92, 0xF9, 0x01, 0x30, 0x10, 0x30, 0xCD, 0xE9, 0x01, 0x04, + 0x71, 0x48, 0x01, 0x22, + 0x98, 0x30, 0x00, 0x90, 0xCD, 0xE9, 0x03, 0x32, 0xD1, 0xE9, 0x04, 0x23, + 0x08, 0x68, 0xFF, 0xF7, + 0x01, 0xFC, 0x01, 0x20, 0x94, 0xE7, 0x30, 0xB5, 0x67, 0x49, 0x02, 0x79, + 0x85, 0xB0, 0x4B, 0x68, + 0x9A, 0x42, 0x03, 0xD1, 0x42, 0x79, 0x8B, 0x68, 0x9A, 0x42, 0x01, 0xD0, + 0x00, 0x20, 0x87, 0xE7, + 0x62, 0x4A, 0x85, 0x79, 0x00, 0x24, 0x82, 0xF8, 0x82, 0x5F, 0xC5, 0x79, + 0x82, 0xF8, 0x83, 0x5F, + 0x85, 0x7A, 0x82, 0xF8, 0x84, 0x5F, 0xC5, 0x7A, 0x82, 0xF8, 0x85, 0x5F, + 0x05, 0x7B, 0x82, 0xF8, + 0x80, 0x5F, 0x45, 0x7B, 0x82, 0xF8, 0x81, 0x5F, 0x59, 0x4A, 0x23, 0x46, + 0x12, 0x68, 0x92, 0xF8, + 0x26, 0x50, 0xA5, 0x2D, 0x03, 0xD1, 0x12, 0xF9, 0x27, 0x4F, 0x92, 0xF9, + 0x01, 0x30, 0x10, 0x30, + 0xCD, 0xE9, 0x01, 0x04, 0x54, 0x48, 0x01, 0x22, 0x00, 0x90, 0xCD, 0xE9, + 0x03, 0x32, 0xD1, 0xE9, + 0x04, 0x23, 0x08, 0x68, 0xFF, 0xF7, 0xC6, 0xFB, 0x01, 0x20, 0x59, 0xE7, + 0x2D, 0xE9, 0xFF, 0x41, + 0x0F, 0x46, 0x15, 0x46, 0x04, 0x46, 0x00, 0x26, 0x40, 0xF2, 0x7A, 0x31, + 0x03, 0xF0, 0x84, 0xF9, + 0x45, 0x48, 0x01, 0x2D, 0x01, 0x79, 0x21, 0x71, 0x01, 0x7A, 0x61, 0x71, + 0x06, 0xD1, 0x44, 0x49, + 0x09, 0x68, 0x8A, 0x7E, 0xA5, 0x2A, 0x01, 0xD1, 0x91, 0xF9, 0x1B, 0x60, + 0x00, 0x22, 0x04, 0xF1, + 0x10, 0x01, 0x3E, 0x4B, 0xCD, 0xE9, 0x00, 0x31, 0xCD, 0xE9, 0x02, 0x62, + 0x05, 0x46, 0x00, 0x68, + 0xD5, 0xE9, 0x04, 0x23, 0xFF, 0xF7, 0x52, 0xFB, 0xA5, 0x20, 0x20, 0x70, + 0x10, 0x20, 0x60, 0x70, + 0x67, 0x80, 0xD5, 0xE9, 0x01, 0x01, 0x48, 0x43, 0x13, 0x30, 0x80, 0x08, + 0x2F, 0xE6, 0x2D, 0xE9, + 0xFF, 0x41, 0x0F, 0x46, 0x15, 0x46, 0x04, 0x46, 0x00, 0x26, 0x40, 0xF2, + 0x7A, 0x31, 0x03, 0xF0, + 0x53, 0xF9, 0x2D, 0x48, 0x01, 0x2D, 0x01, 0x79, 0x21, 0x71, 0x01, 0x7A, + 0x61, 0x71, 0x06, 0xD1, + 0x2B, 0x49, 0x09, 0x68, 0x0A, 0x7F, 0xA5, 0x2A, 0x01, 0xD1, 0x91, 0xF9, + 0x1D, 0x60, 0x00, 0x23, + 0x04, 0xF1, 0x10, 0x01, 0x29, 0x4A, 0xCD, 0xE9, 0x00, 0x21, 0xCD, 0xE9, + 0x02, 0x63, 0x05, 0x46, + 0x00, 0x68, 0xD5, 0xE9, 0x04, 0x23, 0xFF, 0xF7, 0x21, 0xFB, 0xA5, 0x20, + 0x20, 0x70, 0x11, 0x20, + 0x60, 0x70, 0x67, 0x80, 0xD5, 0xE9, 0x01, 0x01, 0x48, 0x43, 0x13, 0x30, + 0x80, 0x08, 0xFE, 0xE5, + 0x2D, 0xE9, 0xFF, 0x41, 0x0F, 0x46, 0x15, 0x46, 0x04, 0x46, 0x00, 0x26, + 0x40, 0xF2, 0x7A, 0x31, + 0x03, 0xF0, 0x22, 0xF9, 0x14, 0x48, 0x01, 0x2D, 0x01, 0x79, 0x21, 0x71, + 0x01, 0x7A, 0x61, 0x71, + 0x07, 0xD1, 0x13, 0x49, 0x09, 0x68, 0x91, 0xF8, 0x24, 0x20, 0xA5, 0x2A, + 0x01, 0xD1, 0x91, 0xF9, + 0x25, 0x60, 0x10, 0x4A, 0x00, 0x23, 0x04, 0xF1, 0x10, 0x01, 0xA0, 0x3A, + 0xCD, 0xE9, 0x00, 0x21, + 0xCD, 0xE9, 0x02, 0x63, 0x05, 0x46, 0x00, 0x68, 0xD5, 0xE9, 0x04, 0x23, + 0xFF, 0xF7, 0xEE, 0xFA, + 0xA5, 0x20, 0x20, 0x70, 0x14, 0x20, 0x60, 0x70, 0x67, 0x80, 0xD5, 0xE9, + 0x01, 0x01, 0x48, 0x43, + 0x13, 0x30, 0x80, 0x08, 0xCB, 0xE5, 0x00, 0x00, 0xB0, 0x07, 0x10, 0x00, + 0x78, 0x8B, 0x01, 0x20, + 0x50, 0x07, 0x10, 0x00, 0x38, 0x99, 0x01, 0x20, 0x68, 0x9A, 0x01, 0x20, + 0x08, 0x92, 0x01, 0x20, + 0x2D, 0xE9, 0xF0, 0x4F, 0x47, 0xF6, 0xFF, 0x77, 0xDD, 0xE9, 0x09, 0xB5, + 0x81, 0x46, 0xFE, 0x43, + 0x01, 0x20, 0x9A, 0x46, 0x84, 0x46, 0x2C, 0x46, 0x15, 0xE0, 0x00, 0xBF, + 0x32, 0xF8, 0x14, 0x30, + 0x31, 0xF8, 0x14, 0x80, 0xA3, 0xEB, 0x08, 0x03, 0x1B, 0xB2, 0xBB, 0x42, + 0x00, 0xDA, 0x1F, 0x46, + 0xB3, 0x42, 0x00, 0xDD, 0x1E, 0x46, 0x00, 0x2B, 0x02, 0xDD, 0x4F, 0xF0, + 0x00, 0x0C, 0x02, 0xE0, + 0x01, 0xDA, 0x4F, 0xF0, 0x00, 0x00, 0x64, 0x1E, 0xE8, 0xD2, 0x20, 0xB1, + 0xBC, 0xF1, 0x00, 0x0F, + 0x01, 0xD0, 0x00, 0x23, 0x09, 0xE0, 0x50, 0xEA, 0x0C, 0x03, 0x06, 0xD0, + 0x20, 0xB9, 0xBC, 0xF1, + 0x00, 0x0F, 0x01, 0xD0, 0x33, 0x46, 0x00, 0xE0, 0x3B, 0x46, 0x00, 0x27, + 0x3C, 0x46, 0x28, 0x46, + 0xCB, 0xF1, 0x00, 0x0C, 0x0E, 0xE0, 0x00, 0xBF, 0x32, 0xF8, 0x10, 0x60, + 0x31, 0xF8, 0x10, 0x80, + 0xA6, 0xEB, 0x08, 0x06, 0xF6, 0x1A, 0x36, 0xB2, 0x56, 0x45, 0x03, 0xDA, + 0x66, 0x45, 0x01, 0xDD, + 0x37, 0x44, 0x64, 0x1C, 0x40, 0x1E, 0xEF, 0xD2, 0x04, 0xB9, 0x01, 0x24, + 0x97, 0xFB, 0xF4, 0xF0, + 0x18, 0x44, 0x04, 0xE0, 0x31, 0xF8, 0x15, 0x20, 0x02, 0x44, 0x29, 0xF8, + 0x15, 0x20, 0x6D, 0x1E, + 0xF8, 0xD2, 0xBD, 0xE8, 0xF0, 0x8F, 0xF0, 0xB5, 0x00, 0x23, 0x06, 0x46, + 0x1D, 0x46, 0x18, 0x46, + 0x0E, 0xE0, 0x00, 0xBF, 0x36, 0xF9, 0x11, 0x40, 0x00, 0x2C, 0x01, 0xDB, + 0x27, 0x46, 0x00, 0xE0, + 0x67, 0x42, 0x97, 0x42, 0x04, 0xDD, 0x00, 0x2C, 0x01, 0xDD, 0x25, 0x44, + 0x00, 0xE0, 0x23, 0x44, + 0x49, 0x1E, 0xEF, 0xD2, 0x00, 0x2B, 0x00, 0xDA, 0x5B, 0x42, 0xAB, 0x42, + 0x00, 0xDD, 0x01, 0x20, + 0xF0, 0xBD, 0x30, 0xB5, 0x07, 0xE0, 0x00, 0xBF, 0x32, 0xF8, 0x13, 0x40, + 0x31, 0xF8, 0x13, 0x50, + 0x64, 0x1B, 0x20, 0xF8, 0x13, 0x40, 0x5B, 0x1E, 0xF6, 0xD2, 0x30, 0xBD, + 0xF0, 0xB4, 0x04, 0x9C, + 0x1C, 0xB9, 0x13, 0xB1, 0xC3, 0xF1, 0x10, 0x04, 0x0E, 0xE0, 0xF0, 0xBC, + 0x52, 0x00, 0x02, 0xF0, + 0xDC, 0xBF, 0x00, 0xBF, 0x30, 0xF9, 0x12, 0x50, 0x31, 0xF9, 0x12, 0x60, + 0x5D, 0x43, 0x06, 0xFB, + 0x04, 0x55, 0x2D, 0x11, 0x20, 0xF8, 0x12, 0x50, 0x52, 0x1E, 0xF3, 0xD2, + 0xF0, 0xBC, 0x70, 0x47, + 0xF0, 0xB4, 0x04, 0x9C, 0x1C, 0xB9, 0x13, 0xB1, 0xC3, 0xF1, 0x80, 0x04, + 0x0E, 0xE0, 0xF0, 0xBC, + 0x52, 0x00, 0x02, 0xF0, 0xC2, 0xBF, 0x00, 0xBF, 0x30, 0xF9, 0x12, 0x50, + 0x31, 0xF9, 0x12, 0x60, + 0x5D, 0x43, 0x06, 0xFB, 0x04, 0x55, 0xED, 0x11, 0x20, 0xF8, 0x12, 0x50, + 0x52, 0x1E, 0xF3, 0xD2, + 0xE4, 0xE7, 0xF0, 0xB5, 0x00, 0x2B, 0x19, 0xD0, 0x14, 0x46, 0x15, 0xE0, + 0x00, 0x27, 0x3E, 0x46, + 0xE5, 0x1A, 0x04, 0xEB, 0x03, 0x0C, 0x08, 0xE0, 0x00, 0x2D, 0x05, 0xDB, + 0x95, 0x42, 0x03, 0xDA, + 0x31, 0xF9, 0x15, 0xE0, 0x76, 0x1C, 0x77, 0x44, 0x6D, 0x1C, 0xAC, 0x45, + 0xF4, 0xDA, 0x1E, 0xB1, + 0x97, 0xFB, 0xF6, 0xF5, 0x20, 0xF8, 0x14, 0x50, 0x64, 0x1E, 0xE7, 0xD2, + 0xF0, 0xBD, 0x70, 0xB5, + 0x0C, 0x46, 0x15, 0x46, 0xA0, 0x42, 0x04, 0xD0, 0x01, 0x46, 0x6A, 0x00, + 0x20, 0x46, 0x02, 0xF0, + 0x8C, 0xFF, 0x00, 0x20, 0x17, 0xE0, 0x01, 0x46, 0x42, 0x1C, 0x07, 0xE0, + 0x34, 0xF9, 0x12, 0x60, + 0x34, 0xF9, 0x11, 0x30, 0x9E, 0x42, 0x00, 0xDA, 0x11, 0x46, 0x52, 0x1C, + 0xAA, 0x42, 0xF5, 0xD3, + 0x88, 0x42, 0x07, 0xD0, 0x34, 0xF8, 0x10, 0x20, 0x34, 0xF8, 0x11, 0x30, + 0x24, 0xF8, 0x10, 0x30, + 0x24, 0xF8, 0x11, 0x20, 0x40, 0x1C, 0xB0, 0xEB, 0x55, 0x0F, 0xE4, 0xD9, + 0xE9, 0x07, 0x25, 0xF0, + 0x01, 0x00, 0x01, 0xD0, 0x20, 0x5E, 0x70, 0xBD, 0x21, 0x5E, 0x20, 0x44, + 0x30, 0xF9, 0x02, 0x0C, + 0x08, 0x44, 0x40, 0x10, 0x70, 0xBD, 0x03, 0x46, 0x00, 0x20, 0x04, 0xE0, + 0x33, 0xF9, 0x11, 0x20, + 0x82, 0x42, 0x00, 0xDD, 0x10, 0x46, 0x49, 0x1E, 0xF8, 0xD2, 0x70, 0x47, + 0x03, 0x46, 0x47, 0xF6, + 0xFF, 0x70, 0x04, 0xE0, 0x33, 0xF9, 0x11, 0x20, 0x82, 0x42, 0x00, 0xDA, + 0x10, 0x46, 0x49, 0x1E, + 0xF8, 0xD2, 0x00, 0x28, 0x00, 0xDA, 0x00, 0x20, 0x70, 0x47, 0x02, 0x46, + 0xB0, 0xF9, 0x00, 0x00, + 0x05, 0xE0, 0x00, 0xBF, 0x32, 0xF9, 0x11, 0x30, 0x83, 0x42, 0x00, 0xDD, + 0x18, 0x46, 0x49, 0x1E, + 0xF8, 0xD2, 0x70, 0x47, 0x70, 0xB5, 0x05, 0x00, 0x03, 0xD0, 0xBD, 0xE8, + 0x70, 0x40, 0x02, 0xF0, + 0xE4, 0xBB, 0xFE, 0x4C, 0x21, 0x46, 0x60, 0x78, 0x09, 0x79, 0x30, 0xB1, + 0x0A, 0x46, 0xFC, 0x49, + 0x01, 0xF1, 0x98, 0x00, 0x02, 0xF0, 0x04, 0xFC, 0x0B, 0xE0, 0x20, 0x78, + 0x02, 0xF0, 0x42, 0xFD, + 0x21, 0x79, 0x4A, 0x00, 0xF6, 0x49, 0x01, 0xEB, 0x40, 0x01, 0xF5, 0x48, + 0x98, 0x30, 0x02, 0xF0, + 0x1C, 0xFF, 0xA0, 0x78, 0xF3, 0x4E, 0x28, 0xB1, 0xF1, 0x48, 0x21, 0x79, + 0x98, 0x30, 0x02, 0xF0, + 0x2F, 0xFD, 0x01, 0xE0, 0xEE, 0x48, 0x98, 0x30, 0xB0, 0x62, 0xE0, 0x78, + 0x86, 0xF8, 0x31, 0x00, + 0x28, 0x46, 0xD2, 0xE7, 0x2D, 0xE9, 0xF0, 0x47, 0xDF, 0xF8, 0xAC, 0xA3, + 0x01, 0x27, 0xB8, 0x46, + 0xDA, 0xF8, 0x00, 0x00, 0x00, 0xF2, 0x5E, 0x64, 0x90, 0xF8, 0xA6, 0x19, + 0x90, 0xF8, 0xA2, 0x59, + 0x01, 0xF0, 0x1F, 0x06, 0x90, 0xF8, 0xA3, 0x19, 0x01, 0xF0, 0x0F, 0x09, + 0x90, 0xF8, 0x82, 0x19, + 0x89, 0x06, 0x09, 0xD5, 0x90, 0xF8, 0x58, 0x16, 0x90, 0xF8, 0x59, 0x06, + 0x0A, 0x22, 0x04, 0xEB, + 0x40, 0x00, 0x02, 0xF0, 0x09, 0xFC, 0x07, 0x46, 0xDA, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0x82, 0x19, + 0x49, 0x06, 0x09, 0xD5, 0x90, 0xF8, 0x68, 0x18, 0x90, 0xF8, 0x69, 0x08, + 0x0A, 0x22, 0x04, 0xEB, + 0x40, 0x00, 0x02, 0xF0, 0xF9, 0xFB, 0x80, 0x46, 0x4F, 0xF4, 0x80, 0x70, + 0x85, 0x42, 0x00, 0xD9, + 0x05, 0x46, 0x1F, 0x2E, 0x00, 0xD9, 0x1F, 0x26, 0x76, 0x1C, 0x75, 0x43, + 0x09, 0xF1, 0x01, 0x00, + 0x45, 0x43, 0xC5, 0xEB, 0x45, 0x20, 0x78, 0x43, 0x00, 0xFB, 0x08, 0xF0, + 0xC0, 0x13, 0xB0, 0xFA, + 0x80, 0xF0, 0xC0, 0xF1, 0x20, 0x00, 0xC0, 0xB2, 0xBD, 0xE8, 0xF0, 0x87, + 0x2D, 0xE9, 0xF0, 0x41, + 0x04, 0x46, 0xEC, 0xF7, 0x61, 0xFA, 0xC2, 0x48, 0xEC, 0xF7, 0x63, 0xFA, + 0xA4, 0xF8, 0x76, 0x00, + 0x02, 0xF0, 0xB2, 0xFB, 0x01, 0x46, 0x20, 0x46, 0xEC, 0xF7, 0xCC, 0xFC, + 0x02, 0xF0, 0xB0, 0xFB, + 0x02, 0x46, 0x0B, 0x46, 0x20, 0x46, 0xEC, 0xF7, 0xE7, 0xFC, 0x20, 0x46, + 0x02, 0xF0, 0xE2, 0xFC, + 0xB9, 0x4D, 0xB4, 0xF8, 0x56, 0x10, 0x28, 0x68, 0xB0, 0xF8, 0xBE, 0x20, + 0x62, 0xF3, 0x09, 0x01, + 0xA4, 0xF8, 0x56, 0x10, 0x90, 0xF8, 0xBD, 0x00, 0x94, 0xF8, 0x55, 0x10, + 0x60, 0xF3, 0x03, 0x01, + 0x84, 0xF8, 0x55, 0x10, 0x04, 0x21, 0x20, 0x46, 0xEC, 0xF7, 0x69, 0xFA, + 0x28, 0x68, 0x90, 0xF8, + 0xA2, 0x09, 0xA0, 0x70, 0x28, 0x68, 0x21, 0x8E, 0xB0, 0xF8, 0xA7, 0x29, + 0x62, 0xF3, 0x08, 0x01, + 0x21, 0x86, 0x90, 0xF8, 0xA3, 0x09, 0x00, 0xF0, 0x0F, 0x01, 0x20, 0x46, + 0xEC, 0xF7, 0xB7, 0xFA, + 0x28, 0x68, 0x34, 0xF8, 0x1A, 0x1F, 0xB0, 0xF8, 0x8E, 0x29, 0x62, 0xF3, + 0x0B, 0x01, 0x24, 0xF8, + 0x12, 0x19, 0xB0, 0xF8, 0x8C, 0x29, 0x21, 0x89, 0x62, 0xF3, 0x0B, 0x01, + 0x21, 0x81, 0xB0, 0xF8, + 0x8A, 0x29, 0xA1, 0x88, 0x62, 0xF3, 0x0B, 0x01, 0xA1, 0x80, 0x90, 0xF8, + 0xA4, 0x29, 0xA1, 0x7A, + 0x62, 0xF3, 0x01, 0x01, 0xA1, 0x72, 0x90, 0xF8, 0xA4, 0x29, 0x92, 0x08, + 0x62, 0xF3, 0x87, 0x11, + 0xA1, 0x72, 0x90, 0xF8, 0x82, 0x19, 0x14, 0xF8, 0x01, 0x2C, 0x61, 0xF3, + 0x00, 0x02, 0x04, 0xF8, + 0x01, 0x2C, 0x90, 0xF8, 0x85, 0x09, 0x60, 0x70, 0x90, 0x48, 0x90, 0xF8, + 0xE8, 0x1E, 0xA1, 0x75, + 0x90, 0xF8, 0xE9, 0x1E, 0x21, 0x77, 0x90, 0xF8, 0xEA, 0x1E, 0xE1, 0x75, + 0x90, 0xF8, 0xEB, 0x1E, + 0x61, 0x77, 0x90, 0xF8, 0xEC, 0x1E, 0x21, 0x76, 0x90, 0xF8, 0xED, 0x0E, + 0xA0, 0x77, 0x88, 0x48, + 0xEC, 0xF7, 0xE7, 0xF9, 0xA4, 0xF8, 0x78, 0x00, 0x85, 0x48, 0x20, 0x30, + 0xEC, 0xF7, 0xE1, 0xF9, + 0xA4, 0xF8, 0x7C, 0x00, 0x28, 0x68, 0x26, 0x7D, 0x90, 0xF8, 0x92, 0x19, + 0x09, 0x09, 0x61, 0xF3, + 0x07, 0x16, 0x26, 0x75, 0x90, 0xF8, 0x97, 0x19, 0x0A, 0x09, 0xA1, 0x7E, + 0x62, 0xF3, 0x07, 0x11, + 0xA1, 0x76, 0x90, 0xF8, 0x93, 0x29, 0x63, 0x7D, 0x62, 0xF3, 0x03, 0x03, + 0x63, 0x75, 0x90, 0xF8, + 0x98, 0x79, 0xE2, 0x7E, 0x67, 0xF3, 0x03, 0x02, 0xE2, 0x76, 0x90, 0xF8, + 0x93, 0x79, 0x3F, 0x09, + 0x67, 0xF3, 0x07, 0x13, 0x63, 0x75, 0x90, 0xF8, 0x98, 0x39, 0x1B, 0x09, + 0x63, 0xF3, 0x07, 0x12, + 0xE2, 0x76, 0x90, 0xF8, 0x92, 0x29, 0x62, 0xF3, 0x00, 0x06, 0x26, 0x75, + 0x90, 0xF8, 0x97, 0x29, + 0x62, 0xF3, 0x00, 0x01, 0xA1, 0x76, 0x90, 0xF8, 0x87, 0x09, 0x01, 0x09, + 0xE0, 0x78, 0x61, 0xF3, + 0x03, 0x00, 0xE0, 0x70, 0x66, 0x48, 0x48, 0x38, 0xEC, 0xF7, 0xA3, 0xF9, + 0xA4, 0xF8, 0x76, 0x00, + 0x63, 0x48, 0x28, 0x38, 0xEC, 0xF7, 0x9D, 0xF9, 0xA4, 0xF8, 0x7A, 0x00, + 0x29, 0x68, 0x91, 0xF8, + 0x84, 0x09, 0xC2, 0x08, 0x14, 0xF8, 0x1F, 0x0F, 0x62, 0xF3, 0x83, 0x00, + 0x20, 0x70, 0x91, 0xF8, + 0x84, 0x29, 0x52, 0x08, 0x62, 0xF3, 0x00, 0x00, 0x20, 0x70, 0x91, 0xF8, + 0x84, 0x29, 0x92, 0x08, + 0x62, 0xF3, 0x41, 0x00, 0x04, 0xF8, 0x27, 0x09, 0x91, 0xF8, 0x83, 0x09, + 0xC0, 0xF3, 0x81, 0x01, + 0x20, 0x46, 0xEC, 0xF7, 0xF9, 0xF9, 0x28, 0x68, 0x90, 0xF8, 0x83, 0x09, + 0x01, 0x09, 0x14, 0xF8, + 0x28, 0x0F, 0x61, 0xF3, 0x04, 0x10, 0x20, 0x70, 0x4E, 0x48, 0xEC, 0xF7, + 0x72, 0xF9, 0xA4, 0xF8, + 0x60, 0x00, 0x4C, 0x48, 0x20, 0x30, 0xEC, 0xF7, 0x6C, 0xF9, 0xA4, 0xF8, + 0x62, 0x00, 0x28, 0x68, + 0x90, 0xF8, 0x82, 0x19, 0xCA, 0x08, 0xE1, 0x7A, 0x62, 0xF3, 0x45, 0x11, + 0xE1, 0x72, 0x90, 0xF8, + 0x83, 0x09, 0x41, 0x08, 0x20, 0x78, 0x61, 0xF3, 0x45, 0x10, 0x04, 0xF8, + 0x28, 0x09, 0x20, 0x46, + 0x02, 0xF0, 0x8D, 0xFB, 0x28, 0x68, 0x90, 0xF8, 0x86, 0x09, 0x81, 0x09, + 0x20, 0x46, 0xEC, 0xF7, + 0xB8, 0xF9, 0x14, 0xF8, 0x32, 0x0F, 0x20, 0xF0, 0x0F, 0x00, 0x0A, 0x30, + 0x20, 0xF0, 0xF0, 0x00, + 0xA0, 0x30, 0x04, 0xF8, 0x1C, 0x09, 0x29, 0x68, 0x91, 0xF8, 0x82, 0x09, + 0x82, 0x09, 0x60, 0x7F, + 0x62, 0xF3, 0x00, 0x00, 0x60, 0x77, 0x91, 0xF8, 0x82, 0x29, 0x52, 0x09, + 0x62, 0xF3, 0x41, 0x00, + 0x60, 0x77, 0x91, 0xF8, 0x88, 0x29, 0x62, 0xF3, 0x82, 0x00, 0x60, 0x77, + 0x91, 0xF8, 0xA5, 0x09, + 0xE2, 0x7D, 0x60, 0xF3, 0x04, 0x02, 0xE2, 0x75, 0x91, 0xF8, 0xA6, 0x09, + 0xA1, 0x7D, 0x60, 0xF3, + 0x04, 0x01, 0x23, 0x48, 0xA1, 0x75, 0x08, 0x38, 0x94, 0xF8, 0x49, 0x10, + 0x40, 0x78, 0x60, 0xF3, + 0x04, 0x01, 0x23, 0x48, 0x84, 0xF8, 0x49, 0x10, 0xE8, 0x30, 0xEC, 0xF7, + 0x1A, 0xF9, 0xA4, 0xF8, + 0x64, 0x00, 0x28, 0x68, 0x21, 0x8B, 0xB0, 0xF8, 0x90, 0x29, 0x62, 0xF3, + 0x0B, 0x01, 0x21, 0x83, + 0x90, 0xF8, 0x86, 0x19, 0xCA, 0x08, 0x94, 0xF8, 0x22, 0x10, 0x62, 0xF3, + 0x02, 0x01, 0x84, 0xF8, + 0x22, 0x10, 0x10, 0xF8, 0xE0, 0x1F, 0x22, 0x7D, 0x61, 0xF3, 0x03, 0x02, + 0x22, 0x75, 0x10, 0xF8, + 0xE0, 0x1B, 0x0A, 0x09, 0x61, 0x7D, 0x62, 0xF3, 0x03, 0x01, 0x61, 0x75, + 0x90, 0xF8, 0xC7, 0x17, + 0xE2, 0x7C, 0x61, 0xF3, 0x02, 0x02, 0xE2, 0x74, 0x90, 0xF8, 0xC2, 0x17, + 0xCA, 0x09, 0xA1, 0x7F, + 0x62, 0xF3, 0x00, 0x01, 0xA1, 0x77, 0x94, 0xF8, 0x49, 0x10, 0x41, 0xF0, + 0x20, 0x01, 0x84, 0xF8, + 0x49, 0x10, 0x90, 0xF8, 0xC4, 0x27, 0xD2, 0x09, 0x0E, 0xE0, 0x00, 0x00, + 0xC8, 0x07, 0x10, 0x00, + 0x7C, 0xA0, 0x01, 0x20, 0xB4, 0x84, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x78, 0x8B, 0x01, 0x20, + 0x18, 0x9A, 0x01, 0x20, 0x48, 0xBF, 0x01, 0x20, 0x62, 0xF3, 0xC7, 0x11, + 0x84, 0xF8, 0x49, 0x10, + 0xB0, 0xF8, 0xDC, 0x27, 0xB4, 0xF8, 0x4A, 0x10, 0x62, 0xF3, 0x08, 0x01, + 0xA4, 0xF8, 0x4A, 0x10, + 0x00, 0x21, 0xE1, 0x64, 0x90, 0xF8, 0xC7, 0x17, 0xCA, 0x08, 0x61, 0x7F, + 0x62, 0xF3, 0xC3, 0x01, + 0x61, 0x77, 0x90, 0xF8, 0xC2, 0x27, 0x12, 0x09, 0x62, 0xF3, 0x04, 0x11, + 0x61, 0x77, 0x90, 0xF8, + 0xE5, 0x17, 0x4A, 0x09, 0x14, 0xF8, 0x0E, 0x1C, 0x62, 0xF3, 0x06, 0x11, + 0x04, 0xF8, 0x0E, 0x1C, + 0x90, 0xF8, 0xC3, 0x17, 0x4A, 0x09, 0xA1, 0x78, 0x62, 0xF3, 0xC3, 0x01, + 0xA1, 0x70, 0x90, 0xF8, + 0xC2, 0x27, 0x52, 0x08, 0x62, 0xF3, 0x04, 0x11, 0xA1, 0x70, 0x90, 0xF8, + 0xC4, 0x07, 0x80, 0x09, + 0x60, 0xF3, 0x86, 0x11, 0xA1, 0x70, 0xBD, 0xE8, 0xF0, 0x81, 0x2D, 0xE9, + 0xF0, 0x41, 0x04, 0x46, + 0x6A, 0x4D, 0x01, 0x20, 0x01, 0x29, 0xA8, 0x70, 0x08, 0xD0, 0x00, 0x26, + 0x68, 0x4F, 0x02, 0x29, + 0x08, 0xD0, 0x03, 0x29, 0x14, 0xD0, 0x04, 0x29, 0x2C, 0xD1, 0x3C, 0xE0, + 0x20, 0x46, 0x00, 0xF0, + 0xC0, 0xF8, 0x27, 0xE0, 0x63, 0x48, 0xFF, 0xF7, 0x19, 0xFE, 0x20, 0x46, + 0x00, 0xF0, 0xB9, 0xF8, + 0xB8, 0x78, 0x94, 0xF8, 0x5F, 0x10, 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, + 0x5F, 0x10, 0x14, 0xE0, + 0x5C, 0x48, 0xFF, 0xF7, 0x0B, 0xFE, 0x20, 0x46, 0x00, 0xF0, 0xAB, 0xF8, + 0xF8, 0x78, 0x94, 0xF8, + 0x5F, 0x10, 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, 0x5F, 0x10, 0x94, 0xF8, + 0x27, 0x00, 0x20, 0xF0, + 0x02, 0x00, 0x40, 0xF0, 0x01, 0x00, 0x84, 0xF8, 0x27, 0x00, 0x00, 0x21, + 0x20, 0x46, 0xEC, 0xF7, + 0xEE, 0xF8, 0xAE, 0x70, 0x20, 0x46, 0x02, 0xF0, 0xD9, 0xFA, 0x94, 0xF8, + 0x27, 0x00, 0x40, 0xF3, + 0x00, 0x00, 0x40, 0x1C, 0xE8, 0x70, 0x4C, 0x48, 0x00, 0x68, 0x90, 0xF8, + 0x83, 0x09, 0xC0, 0xF3, + 0x80, 0x10, 0x68, 0x70, 0xAF, 0xE7, 0x20, 0x46, 0x00, 0xF0, 0x83, 0xF8, + 0x14, 0xF8, 0x37, 0x0F, + 0x40, 0xF0, 0x10, 0x00, 0x04, 0xF8, 0x1F, 0x09, 0xE0, 0x7E, 0x20, 0xF0, + 0x23, 0x00, 0xE0, 0x76, + 0x34, 0xF8, 0x0C, 0x0C, 0x6F, 0xF3, 0x0B, 0x00, 0x10, 0x30, 0x24, 0xF8, + 0x0C, 0x0C, 0x34, 0xF8, + 0x08, 0x0C, 0x6F, 0xF3, 0x0B, 0x00, 0x40, 0x30, 0x24, 0xF8, 0x08, 0x0C, + 0x08, 0x20, 0x04, 0xF8, + 0x16, 0x0C, 0x94, 0xF8, 0x47, 0x00, 0x20, 0xF0, 0x1F, 0x00, 0x84, 0xF8, + 0x47, 0x00, 0x34, 0xF8, + 0x18, 0x0F, 0x6F, 0xF3, 0x08, 0x00, 0x24, 0xF8, 0x03, 0x0B, 0x20, 0x78, + 0x40, 0xF0, 0x0C, 0x00, + 0x04, 0xF8, 0x0B, 0x09, 0x20, 0x78, 0x40, 0xF0, 0x20, 0x00, 0x04, 0xF8, + 0x28, 0x09, 0xB8, 0xE7, + 0x38, 0xB5, 0x02, 0xF0, 0x69, 0xF9, 0x00, 0x90, 0x04, 0x21, 0x68, 0x46, + 0xEC, 0xF7, 0xBB, 0xFC, + 0x26, 0x49, 0x27, 0x4D, 0x08, 0x71, 0x00, 0x20, 0x28, 0x60, 0x28, 0x71, + 0x01, 0x24, 0xE0, 0xB2, + 0xFF, 0xF7, 0x50, 0xFD, 0x28, 0x55, 0x64, 0x1C, 0x05, 0x2C, 0xF8, 0xDB, + 0x21, 0x48, 0xFF, 0xF7, + 0x95, 0xFD, 0x38, 0xBD, 0x30, 0xB5, 0x01, 0x7A, 0xA9, 0xB0, 0x79, 0xB3, + 0x68, 0x46, 0xFF, 0xF7, + 0x5C, 0xFF, 0x9D, 0xF8, 0x12, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x02, 0xF0, + 0xB7, 0xF9, 0x1A, 0x4C, + 0x20, 0x68, 0x00, 0xF2, 0x5E, 0x63, 0x00, 0xF6, 0x6E, 0x05, 0x90, 0xF8, + 0x58, 0x16, 0x90, 0xF8, + 0x59, 0x06, 0x03, 0xEB, 0x40, 0x00, 0x02, 0xF0, 0x7A, 0xF9, 0x20, 0x68, + 0x90, 0xF8, 0x68, 0x18, + 0x90, 0xF8, 0x69, 0x08, 0x05, 0xEB, 0x40, 0x00, 0x02, 0xF0, 0x88, 0xF9, + 0x0B, 0x48, 0x41, 0x78, + 0x01, 0xB1, 0x02, 0x21, 0x01, 0x70, 0xC9, 0xB2, 0x68, 0x46, 0xEC, 0xF7, + 0x7F, 0xFA, 0x0B, 0x49, + 0x68, 0x46, 0xEC, 0xF7, 0xB0, 0xFA, 0x00, 0x20, 0x29, 0xB0, 0x30, 0xBD, + 0xFF, 0xE7, 0x01, 0x20, + 0xFA, 0xE7, 0xA4, 0x22, 0x03, 0x49, 0x02, 0xF0, 0x18, 0xBC, 0x00, 0x00, + 0xC8, 0x07, 0x10, 0x00, + 0x74, 0xA0, 0x01, 0x20, 0xE0, 0x7E, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x95, 0x42, 0x01, 0x00, + 0x10, 0xB5, 0x04, 0x00, 0x03, 0xD0, 0xBD, 0xE8, 0x10, 0x40, 0x02, 0xF0, + 0xB6, 0xB8, 0xFE, 0x48, + 0x02, 0x46, 0x81, 0x78, 0x52, 0x78, 0x29, 0xB1, 0xFC, 0x49, 0xA1, 0xF1, + 0x0A, 0x00, 0x02, 0xF0, + 0xD7, 0xF8, 0x0B, 0xE0, 0x03, 0x78, 0x00, 0x21, 0x01, 0x2B, 0x00, 0xD8, + 0x11, 0x46, 0xF7, 0x48, + 0x52, 0x00, 0x00, 0xEB, 0x41, 0x01, 0x0A, 0x38, 0x02, 0xF0, 0xEF, 0xFB, + 0xF3, 0x48, 0xF4, 0x49, + 0x0A, 0x38, 0xC8, 0x62, 0x20, 0x46, 0xDE, 0xE7, 0x2D, 0xE9, 0xF0, 0x47, + 0xDF, 0xF8, 0xC4, 0xA3, + 0x01, 0x27, 0xB8, 0x46, 0xDA, 0xF8, 0x00, 0x00, 0x00, 0xF2, 0x5E, 0x64, + 0x90, 0xF8, 0x22, 0x1A, + 0x90, 0xF8, 0x1E, 0x5A, 0x01, 0xF0, 0x1F, 0x06, 0x90, 0xF8, 0x1F, 0x1A, + 0x01, 0xF0, 0x0F, 0x09, + 0x90, 0xF8, 0x02, 0x1A, 0x89, 0x06, 0x09, 0xD5, 0x90, 0xF8, 0x5C, 0x16, + 0x90, 0xF8, 0x5D, 0x06, + 0x0A, 0x22, 0x04, 0xEB, 0x40, 0x00, 0x02, 0xF0, 0xE7, 0xF8, 0x07, 0x46, + 0xDA, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0x02, 0x1A, 0x49, 0x06, 0x09, 0xD5, 0x90, 0xF8, 0x6C, 0x18, + 0x90, 0xF8, 0x6D, 0x08, + 0x0A, 0x22, 0x04, 0xEB, 0x40, 0x00, 0x02, 0xF0, 0xD7, 0xF8, 0x80, 0x46, + 0x4F, 0xF4, 0x80, 0x70, + 0x85, 0x42, 0x00, 0xD9, 0x05, 0x46, 0x1F, 0x2E, 0x00, 0xD9, 0x1F, 0x26, + 0x76, 0x1C, 0x75, 0x43, + 0x09, 0xF1, 0x01, 0x00, 0x45, 0x43, 0xC5, 0xEB, 0x45, 0x20, 0x78, 0x43, + 0x00, 0xFB, 0x08, 0xF0, + 0xC0, 0x13, 0xB0, 0xFA, 0x80, 0xF0, 0xC0, 0xF1, 0x20, 0x00, 0xC0, 0xB2, + 0xBD, 0xE8, 0xF0, 0x87, + 0x2D, 0xE9, 0xF0, 0x41, 0x04, 0x46, 0xEB, 0xF7, 0x3F, 0xFF, 0xC8, 0x48, + 0xEB, 0xF7, 0x41, 0xFF, + 0xA4, 0xF8, 0x76, 0x00, 0x02, 0xF0, 0xA5, 0xF8, 0x01, 0x46, 0x20, 0x46, + 0xEC, 0xF7, 0xAA, 0xF9, + 0x02, 0xF0, 0xA4, 0xF8, 0x02, 0x46, 0x0B, 0x46, 0x20, 0x46, 0xEC, 0xF7, + 0xC5, 0xF9, 0x04, 0x21, + 0x20, 0x46, 0xEB, 0xF7, 0x5C, 0xFF, 0xBF, 0x4D, 0x28, 0x68, 0x90, 0xF8, + 0x1E, 0x0A, 0xA0, 0x70, + 0x28, 0x68, 0x21, 0x8E, 0xB0, 0xF8, 0x23, 0x2A, 0x62, 0xF3, 0x08, 0x01, + 0x21, 0x86, 0x90, 0xF8, + 0x1F, 0x0A, 0x00, 0xF0, 0x0F, 0x01, 0x20, 0x46, 0xEB, 0xF7, 0xA9, 0xFF, + 0x28, 0x68, 0x34, 0xF8, + 0x1A, 0x1F, 0xB0, 0xF8, 0x0E, 0x2A, 0x62, 0xF3, 0x0B, 0x01, 0x24, 0xF8, + 0x12, 0x19, 0xB0, 0xF8, + 0x0C, 0x2A, 0x21, 0x89, 0x62, 0xF3, 0x0B, 0x01, 0x21, 0x81, 0xB0, 0xF8, + 0x0A, 0x2A, 0xA1, 0x88, + 0x62, 0xF3, 0x0B, 0x01, 0xA1, 0x80, 0x90, 0xF8, 0x20, 0x2A, 0xA1, 0x7A, + 0x62, 0xF3, 0x01, 0x01, + 0xA1, 0x72, 0x90, 0xF8, 0x20, 0x2A, 0x92, 0x08, 0x62, 0xF3, 0x87, 0x11, + 0xA1, 0x72, 0x90, 0xF8, + 0x02, 0x1A, 0x14, 0xF8, 0x01, 0x2C, 0x61, 0xF3, 0x00, 0x02, 0x04, 0xF8, + 0x01, 0x2C, 0x90, 0xF8, + 0x05, 0x0A, 0x60, 0x70, 0xA0, 0x48, 0x90, 0xF8, 0x80, 0x1F, 0xA1, 0x75, + 0x90, 0xF8, 0x81, 0x1F, + 0x21, 0x77, 0x90, 0xF8, 0x82, 0x1F, 0xE1, 0x75, 0x90, 0xF8, 0x83, 0x1F, + 0x61, 0x77, 0x90, 0xF8, + 0x84, 0x1F, 0x21, 0x76, 0x90, 0xF8, 0x85, 0x0F, 0xA0, 0x77, 0x98, 0x48, + 0xEB, 0xF7, 0xD9, 0xFE, + 0xA4, 0xF8, 0x78, 0x00, 0x95, 0x48, 0x20, 0x30, 0xEB, 0xF7, 0xD3, 0xFE, + 0xA4, 0xF8, 0x7C, 0x00, + 0x28, 0x68, 0x23, 0x7D, 0x90, 0xF8, 0x12, 0x1A, 0x09, 0x09, 0x61, 0xF3, + 0x07, 0x13, 0x23, 0x75, + 0x90, 0xF8, 0x17, 0x1A, 0xA6, 0x7E, 0x09, 0x09, 0x61, 0xF3, 0x07, 0x16, + 0xA6, 0x76, 0x90, 0xF8, + 0x13, 0x1A, 0x62, 0x7D, 0x61, 0xF3, 0x03, 0x02, 0x62, 0x75, 0x90, 0xF8, + 0x18, 0x7A, 0xE1, 0x7E, + 0x67, 0xF3, 0x03, 0x01, 0xE1, 0x76, 0x90, 0xF8, 0x13, 0x7A, 0x3F, 0x09, + 0x67, 0xF3, 0x07, 0x12, + 0x62, 0x75, 0x90, 0xF8, 0x18, 0x2A, 0x12, 0x09, 0x62, 0xF3, 0x07, 0x11, + 0xE1, 0x76, 0x90, 0xF8, + 0x12, 0x1A, 0x61, 0xF3, 0x00, 0x03, 0x23, 0x75, 0x90, 0xF8, 0x17, 0x1A, + 0x61, 0xF3, 0x00, 0x06, + 0xA6, 0x76, 0x90, 0xF8, 0x07, 0x0A, 0x01, 0x09, 0xE0, 0x78, 0x61, 0xF3, + 0x03, 0x00, 0xE0, 0x70, + 0x76, 0x48, 0x48, 0x38, 0xEB, 0xF7, 0x95, 0xFE, 0xA4, 0xF8, 0x76, 0x00, + 0x73, 0x48, 0x28, 0x38, + 0xEB, 0xF7, 0x8F, 0xFE, 0xA4, 0xF8, 0x7A, 0x00, 0x28, 0x68, 0x90, 0xF8, + 0x04, 0x1A, 0xCA, 0x08, + 0x14, 0xF8, 0x1F, 0x1F, 0x62, 0xF3, 0x83, 0x01, 0x41, 0xF0, 0x01, 0x01, + 0x21, 0x70, 0x90, 0xF8, + 0x04, 0x2A, 0x92, 0x08, 0x62, 0xF3, 0x41, 0x01, 0x04, 0xF8, 0x27, 0x19, + 0x90, 0xF8, 0x03, 0x0A, + 0xC0, 0xF3, 0x81, 0x01, 0x20, 0x46, 0xEB, 0xF7, 0xEF, 0xFE, 0x28, 0x68, + 0x90, 0xF8, 0x03, 0x0A, + 0x01, 0x09, 0x14, 0xF8, 0x28, 0x0F, 0x61, 0xF3, 0x04, 0x10, 0x20, 0x70, + 0x60, 0x48, 0xEB, 0xF7, + 0x68, 0xFE, 0xA4, 0xF8, 0x60, 0x00, 0x5E, 0x48, 0x20, 0x30, 0xEB, 0xF7, + 0x62, 0xFE, 0xA4, 0xF8, + 0x62, 0x00, 0x28, 0x68, 0x90, 0xF8, 0x02, 0x1A, 0xCA, 0x08, 0xE1, 0x7A, + 0x62, 0xF3, 0x45, 0x11, + 0xE1, 0x72, 0x90, 0xF8, 0x03, 0x0A, 0x41, 0x08, 0x20, 0x78, 0x61, 0xF3, + 0x45, 0x10, 0x04, 0xF8, + 0x28, 0x09, 0x20, 0x46, 0x02, 0xF0, 0x4A, 0xF8, 0x28, 0x68, 0x90, 0xF8, + 0x06, 0x0A, 0x81, 0x09, + 0x20, 0x46, 0xEB, 0xF7, 0xAE, 0xFE, 0x14, 0xF8, 0x32, 0x0F, 0x20, 0xF0, + 0x0F, 0x00, 0x0A, 0x30, + 0x20, 0xF0, 0xF0, 0x00, 0xA0, 0x30, 0x04, 0xF8, 0x1C, 0x09, 0x29, 0x68, + 0x91, 0xF8, 0x02, 0x0A, + 0x82, 0x09, 0x60, 0x7F, 0x62, 0xF3, 0x00, 0x00, 0x60, 0x77, 0x91, 0xF8, + 0x02, 0x2A, 0x52, 0x09, + 0x62, 0xF3, 0x41, 0x00, 0x60, 0x77, 0x91, 0xF8, 0x08, 0x2A, 0x62, 0xF3, + 0x82, 0x00, 0x60, 0x77, + 0x91, 0xF8, 0x21, 0x0A, 0xE2, 0x7D, 0x60, 0xF3, 0x04, 0x02, 0xE2, 0x75, + 0x91, 0xF8, 0x22, 0x0A, + 0xA1, 0x7D, 0x60, 0xF3, 0x04, 0x01, 0x35, 0x48, 0xA1, 0x75, 0x10, 0x38, + 0x94, 0xF8, 0x49, 0x10, + 0x40, 0x78, 0x60, 0xF3, 0x04, 0x01, 0x35, 0x48, 0x84, 0xF8, 0x49, 0x10, + 0x50, 0x30, 0xEB, 0xF7, + 0x10, 0xFE, 0xA4, 0xF8, 0x64, 0x00, 0x28, 0x68, 0x34, 0xF8, 0x18, 0x1F, + 0xB0, 0xF8, 0x10, 0x2A, + 0x62, 0xF3, 0x0B, 0x01, 0x24, 0xF8, 0x0A, 0x1B, 0x90, 0xF8, 0x06, 0x1A, + 0xCA, 0x08, 0x21, 0x78, + 0x62, 0xF3, 0x02, 0x01, 0x04, 0xF8, 0x0E, 0x19, 0x10, 0xF8, 0xE0, 0x1F, + 0x22, 0x78, 0x61, 0xF3, + 0x03, 0x02, 0x04, 0xF8, 0x01, 0x2B, 0x01, 0x78, 0x0A, 0x09, 0x21, 0x78, + 0x62, 0xF3, 0x03, 0x01, + 0x04, 0xF8, 0x02, 0x19, 0x90, 0xF8, 0x27, 0x19, 0x22, 0x78, 0x61, 0xF3, + 0x02, 0x02, 0x04, 0xF8, + 0x0B, 0x2B, 0x90, 0xF8, 0x22, 0x19, 0xCA, 0x09, 0x21, 0x78, 0x62, 0xF3, + 0x00, 0x01, 0x04, 0xF8, + 0x0E, 0x1B, 0x14, 0xF8, 0x1D, 0x1F, 0x41, 0xF0, 0x20, 0x01, 0x21, 0x70, + 0x90, 0xF8, 0x24, 0x29, + 0xD2, 0x09, 0x62, 0xF3, 0xC7, 0x11, 0x04, 0xF8, 0x01, 0x1B, 0xB0, 0xF8, + 0x3C, 0x29, 0x21, 0x88, + 0x62, 0xF3, 0x08, 0x01, 0x24, 0xF8, 0x02, 0x1B, 0x00, 0x21, 0x44, 0xF8, + 0x2F, 0x19, 0x90, 0xF8, + 0x27, 0x19, 0xCA, 0x08, 0x21, 0x78, 0x62, 0xF3, 0xC3, 0x01, 0x21, 0x70, + 0x90, 0xF8, 0x22, 0x29, + 0x12, 0x09, 0x62, 0xF3, 0x04, 0x11, 0x04, 0xF8, 0x0C, 0x19, 0x14, 0xF8, + 0x1F, 0x19, 0x21, 0xF0, + 0x10, 0x01, 0xE1, 0x77, 0x0E, 0xE0, 0x00, 0x00, 0xCD, 0x07, 0x10, 0x00, + 0x70, 0xA1, 0x01, 0x20, + 0xB4, 0x84, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x78, 0x8B, 0x01, 0x20, + 0xB0, 0x9A, 0x01, 0x20, + 0x48, 0xBF, 0x01, 0x20, 0x90, 0xF8, 0x41, 0x19, 0x4A, 0x09, 0x21, 0x78, + 0x62, 0xF3, 0x06, 0x11, + 0x21, 0x70, 0x90, 0xF8, 0x23, 0x19, 0x4A, 0x09, 0x21, 0x7C, 0x62, 0xF3, + 0xC3, 0x01, 0x21, 0x74, + 0x90, 0xF8, 0x22, 0x29, 0x52, 0x08, 0x62, 0xF3, 0x04, 0x11, 0x21, 0x74, + 0x90, 0xF8, 0x24, 0x09, + 0x80, 0x09, 0x60, 0xF3, 0x86, 0x11, 0x21, 0x74, 0xBD, 0xE8, 0xF0, 0x81, + 0xF8, 0xB5, 0x01, 0xF0, + 0xF0, 0xFE, 0x00, 0x90, 0x04, 0x21, 0x68, 0x46, 0xEC, 0xF7, 0x2D, 0xFA, + 0x45, 0x4E, 0x46, 0x4D, + 0x70, 0x70, 0x00, 0x20, 0x28, 0x60, 0x28, 0x71, 0x01, 0x24, 0xE0, 0xB2, + 0xFF, 0xF7, 0xE4, 0xFD, + 0x28, 0x55, 0x64, 0x1C, 0x05, 0x2C, 0xF8, 0xDB, 0x40, 0x48, 0xFF, 0xF7, + 0x29, 0xFE, 0x40, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x03, 0x0A, 0xC0, 0xF3, 0x80, 0x10, 0xB0, 0x70, + 0xF8, 0xBD, 0x30, 0xB5, + 0x81, 0x7A, 0xA9, 0xB0, 0x79, 0xB3, 0x68, 0x46, 0x00, 0xF0, 0x30, 0xF8, + 0x9D, 0xF8, 0x12, 0x00, + 0x00, 0xF0, 0x03, 0x00, 0x01, 0xF0, 0x22, 0xFF, 0x35, 0x4C, 0x20, 0x68, + 0x00, 0xF2, 0x5E, 0x63, + 0x00, 0xF6, 0x6E, 0x05, 0x90, 0xF8, 0x5C, 0x16, 0x90, 0xF8, 0x5D, 0x06, + 0x03, 0xEB, 0x40, 0x00, + 0x01, 0xF0, 0xE5, 0xFE, 0x20, 0x68, 0x90, 0xF8, 0x6C, 0x18, 0x90, 0xF8, + 0x6D, 0x08, 0x05, 0xEB, + 0x40, 0x00, 0x01, 0xF0, 0xF3, 0xFE, 0x27, 0x48, 0x81, 0x78, 0x01, 0xB1, + 0x02, 0x21, 0x01, 0x70, + 0xC9, 0xB2, 0x68, 0x46, 0xEB, 0xF7, 0xEA, 0xFF, 0x26, 0x49, 0x68, 0x46, + 0xEC, 0xF7, 0x1B, 0xF8, + 0x00, 0x20, 0x29, 0xB0, 0x30, 0xBD, 0xFF, 0xE7, 0x01, 0x20, 0xFA, 0xE7, + 0x70, 0xB5, 0x01, 0x29, + 0x20, 0xD0, 0x1D, 0x4D, 0x03, 0x29, 0x21, 0xD0, 0x04, 0x29, 0x2E, 0xD1, + 0x04, 0x46, 0x1B, 0x48, + 0xFF, 0xF7, 0xDE, 0xFD, 0x20, 0x46, 0x00, 0xF0, 0x29, 0xF8, 0x28, 0x79, + 0x94, 0xF8, 0x5F, 0x10, + 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, 0x5F, 0x10, 0x94, 0xF8, 0x27, 0x00, + 0x20, 0xF0, 0x02, 0x00, + 0x40, 0xF0, 0x01, 0x00, 0x84, 0xF8, 0x27, 0x00, 0x20, 0x46, 0xBD, 0xE8, + 0x70, 0x40, 0x00, 0x21, + 0xEB, 0xF7, 0x9D, 0xBD, 0xBD, 0xE8, 0x70, 0x40, 0x00, 0xF0, 0x10, 0xB8, + 0x04, 0x46, 0x0B, 0x48, + 0xFF, 0xF7, 0xBE, 0xFD, 0x20, 0x46, 0x00, 0xF0, 0x09, 0xF8, 0xE8, 0x78, + 0x94, 0xF8, 0x5F, 0x10, + 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, 0x5F, 0x10, 0xE6, 0xE7, 0x70, 0xBD, + 0xA4, 0x22, 0x03, 0x49, + 0x02, 0xF0, 0x4B, 0xB9, 0xCD, 0x07, 0x10, 0x00, 0x60, 0xA1, 0x01, 0x20, + 0x84, 0x7F, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0xF1, 0x48, 0x01, 0x00, 0x10, 0xB5, 0x04, 0x00, + 0x03, 0xD0, 0xBD, 0xE8, + 0x10, 0x40, 0x01, 0xF0, 0xEA, 0xBD, 0x23, 0x48, 0x23, 0x49, 0x00, 0x78, + 0x42, 0x00, 0x01, 0xEB, + 0x40, 0x01, 0x21, 0x48, 0x98, 0x30, 0x02, 0xF0, 0x30, 0xF9, 0x1F, 0x48, + 0x1F, 0x49, 0x98, 0x30, + 0x48, 0x62, 0x20, 0x46, 0xEB, 0xE7, 0x38, 0xB5, 0x01, 0xF0, 0x26, 0xFE, + 0x00, 0x90, 0x04, 0x21, + 0x68, 0x46, 0xEC, 0xF7, 0x78, 0xF9, 0x17, 0x49, 0x19, 0x4C, 0x08, 0x70, + 0x20, 0x46, 0x00, 0xF0, + 0x19, 0xFB, 0x18, 0x48, 0x01, 0x68, 0xA0, 0x7C, 0x91, 0xF8, 0x50, 0x21, + 0x62, 0xF3, 0x01, 0x00, + 0xA0, 0x74, 0x91, 0xF8, 0x50, 0x11, 0x89, 0x08, 0x61, 0xF3, 0x87, 0x10, + 0xA0, 0x74, 0x38, 0xBD, + 0x10, 0xB5, 0x0F, 0x4C, 0xC0, 0x79, 0x98, 0xB1, 0x20, 0x46, 0x01, 0xF0, + 0x2F, 0xFF, 0xA0, 0x7C, + 0x00, 0xF0, 0x03, 0x00, 0x01, 0xF0, 0x72, 0xFE, 0x00, 0xF0, 0x8D, 0xFB, + 0x04, 0x21, 0x20, 0x46, + 0xEB, 0xF7, 0x54, 0xFF, 0x08, 0x49, 0x20, 0x46, 0xEB, 0xF7, 0x85, 0xFF, + 0x00, 0x20, 0x10, 0xBD, + 0x01, 0x20, 0x10, 0xBD, 0xD0, 0x07, 0x10, 0x00, 0x80, 0xA1, 0x01, 0x20, + 0xB4, 0x84, 0x10, 0x00, + 0x28, 0x80, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, 0x89, 0x4E, 0x01, 0x00, + 0xFE, 0x49, 0xC8, 0x68, + 0x40, 0x1C, 0xC8, 0x60, 0x02, 0x28, 0x03, 0xD2, 0xFC, 0x49, 0x51, 0xF8, + 0x20, 0x00, 0x00, 0x47, + 0x00, 0x20, 0x01, 0xF0, 0x8A, 0xBD, 0x00, 0x28, 0x01, 0xD1, 0xEB, 0xF7, + 0x55, 0xBF, 0x70, 0x47, + 0xF5, 0x49, 0x10, 0xB5, 0x0A, 0x79, 0x01, 0x20, 0x52, 0x1C, 0xD2, 0xB2, + 0x0A, 0x71, 0x0B, 0x7A, + 0x9A, 0x42, 0x0A, 0xD8, 0x48, 0x7A, 0x48, 0xB1, 0xEB, 0xF7, 0xB6, 0xFE, + 0x03, 0x20, 0xEB, 0xF7, + 0x91, 0xF9, 0xEF, 0x48, 0xEB, 0xF7, 0xA4, 0xFE, 0x00, 0x20, 0x10, 0xBD, + 0xEB, 0xF7, 0x3C, 0xFF, + 0xFA, 0xE7, 0x70, 0xB5, 0x18, 0xB1, 0xBD, 0xE8, 0x70, 0x40, 0x01, 0xF0, + 0x66, 0xBD, 0xE6, 0x4C, + 0x20, 0x7A, 0x08, 0xB1, 0xE7, 0x4D, 0x01, 0xE0, 0xE6, 0x4D, 0x76, 0x3D, + 0xA0, 0x78, 0xE6, 0x49, + 0x82, 0x00, 0x01, 0xF5, 0xAE, 0x70, 0x02, 0xF0, 0xED, 0xF8, 0x60, 0x79, + 0x28, 0xB1, 0xA2, 0x78, + 0xE1, 0x49, 0x28, 0x46, 0x01, 0xF0, 0x7C, 0xFD, 0x0C, 0xE0, 0xA1, 0x78, + 0x60, 0x78, 0x01, 0xF0, + 0xB9, 0xFE, 0xA1, 0x78, 0xC0, 0xB2, 0x4A, 0x00, 0xDB, 0x49, 0x01, 0xEB, + 0x40, 0x01, 0x28, 0x46, + 0x02, 0xF0, 0x93, 0xF8, 0xD7, 0x48, 0x23, 0x79, 0xA2, 0x78, 0x29, 0x46, + 0x76, 0x38, 0x01, 0xF0, + 0x77, 0xFD, 0xFF, 0xF7, 0xB5, 0xFF, 0x00, 0x28, 0x15, 0xD0, 0xA0, 0x79, + 0xD3, 0x4D, 0x01, 0x28, + 0x0B, 0xD0, 0xD0, 0x48, 0x76, 0x38, 0xA8, 0x61, 0xE0, 0x79, 0x85, 0xF8, + 0x30, 0x00, 0x20, 0x79, + 0x85, 0xF8, 0x20, 0x00, 0xBD, 0xE8, 0x70, 0x40, 0x90, 0xE7, 0xCA, 0x48, + 0xA1, 0x78, 0x76, 0x38, + 0x01, 0xF0, 0x8E, 0xFE, 0xEF, 0xE7, 0x70, 0xBD, 0x70, 0xB5, 0x18, 0xB1, + 0xBD, 0xE8, 0x70, 0x40, + 0x01, 0xF0, 0x1B, 0xBD, 0xC0, 0x4C, 0x20, 0x7A, 0x08, 0xB1, 0xC2, 0x4D, + 0x01, 0xE0, 0xC1, 0x4D, + 0x4C, 0x3D, 0xE0, 0x78, 0xC0, 0x49, 0x82, 0x00, 0x01, 0xF5, 0xD8, 0x70, + 0x02, 0xF0, 0xA2, 0xF8, + 0x60, 0x79, 0x28, 0xB1, 0xE2, 0x78, 0xBC, 0x49, 0x28, 0x46, 0x01, 0xF0, + 0x31, 0xFD, 0x0C, 0xE0, + 0xE1, 0x78, 0x60, 0x78, 0x01, 0xF0, 0x74, 0xFE, 0xE1, 0x78, 0xC0, 0xB2, + 0x4A, 0x00, 0xB6, 0x49, + 0x01, 0xEB, 0x40, 0x01, 0x28, 0x46, 0x02, 0xF0, 0x48, 0xF8, 0xB2, 0x48, + 0x23, 0x79, 0xE2, 0x78, + 0x29, 0x46, 0x4C, 0x38, 0x01, 0xF0, 0x2C, 0xFD, 0xFF, 0xF7, 0x6A, 0xFF, + 0x00, 0x28, 0x15, 0xD0, + 0xA0, 0x79, 0xAE, 0x4D, 0x01, 0x28, 0x0B, 0xD0, 0xAA, 0x48, 0x4C, 0x38, + 0xE8, 0x61, 0xE0, 0x79, + 0x85, 0xF8, 0x30, 0x00, 0x20, 0x79, 0x85, 0xF8, 0x21, 0x00, 0xBD, 0xE8, + 0x70, 0x40, 0x45, 0xE7, + 0xA4, 0x48, 0xE1, 0x78, 0x4C, 0x38, 0x01, 0xF0, 0x44, 0xFE, 0xEF, 0xE7, + 0x70, 0xBD, 0x2D, 0xE9, + 0xF0, 0x5F, 0xA3, 0x48, 0x01, 0x27, 0xB8, 0x46, 0x00, 0x68, 0x00, 0xF2, + 0x5E, 0x64, 0x90, 0xF8, + 0x33, 0x11, 0x90, 0xF8, 0x4E, 0x51, 0xC1, 0xF3, 0x80, 0x1B, 0x90, 0xF8, + 0x55, 0x11, 0x01, 0xF0, + 0x03, 0x0A, 0x90, 0xF8, 0x52, 0x11, 0x01, 0xF0, 0x1F, 0x06, 0x90, 0xF8, + 0x4F, 0x11, 0x01, 0xF0, + 0x0F, 0x09, 0x90, 0xF8, 0x32, 0x11, 0x89, 0x06, 0x09, 0xD5, 0x90, 0xF8, + 0x56, 0x16, 0x90, 0xF8, + 0x57, 0x06, 0x0A, 0x22, 0x04, 0xEB, 0x40, 0x00, 0x01, 0xF0, 0x1E, 0xFD, + 0x07, 0x46, 0x90, 0x48, + 0x00, 0x68, 0x90, 0xF8, 0x32, 0x11, 0x49, 0x06, 0x09, 0xD5, 0x90, 0xF8, + 0x66, 0x18, 0x90, 0xF8, + 0x67, 0x08, 0x0A, 0x22, 0x04, 0xEB, 0x40, 0x00, 0x01, 0xF0, 0x0E, 0xFD, + 0x80, 0x46, 0x4F, 0xF4, + 0x80, 0x70, 0x85, 0x42, 0x00, 0xD9, 0x05, 0x46, 0x1F, 0x2E, 0x00, 0xD9, + 0x1F, 0x26, 0x76, 0x1C, + 0x75, 0x43, 0x09, 0xF1, 0x01, 0x00, 0x45, 0x43, 0xC5, 0xEB, 0x45, 0x20, + 0x78, 0x43, 0x00, 0xFB, + 0x08, 0xF0, 0x0A, 0xF1, 0x01, 0x01, 0x48, 0x43, 0x0B, 0xF1, 0x01, 0x01, + 0x48, 0x43, 0xC0, 0x13, + 0xB0, 0xFA, 0x80, 0xF0, 0xC0, 0xF1, 0x20, 0x00, 0xC0, 0xB2, 0xBD, 0xE8, + 0xF0, 0x9F, 0x2D, 0xE9, + 0xF0, 0x41, 0x04, 0x46, 0xEB, 0xF7, 0x70, 0xFB, 0x73, 0x48, 0xEB, 0xF7, + 0x72, 0xFB, 0xA4, 0xF8, + 0x76, 0x00, 0x01, 0xF0, 0xC1, 0xFC, 0x01, 0x46, 0x20, 0x46, 0xEB, 0xF7, + 0xDB, 0xFD, 0x01, 0xF0, + 0xBF, 0xFC, 0x02, 0x46, 0x0B, 0x46, 0x20, 0x46, 0xEB, 0xF7, 0xF6, 0xFD, + 0x20, 0x46, 0x01, 0xF0, + 0xF1, 0xFD, 0x6B, 0x4D, 0xB4, 0xF8, 0x56, 0x10, 0x28, 0x68, 0xB0, 0xF8, + 0xBE, 0x20, 0x62, 0xF3, + 0x09, 0x01, 0xA4, 0xF8, 0x56, 0x10, 0x90, 0xF8, 0xBD, 0x10, 0x94, 0xF8, + 0x55, 0x00, 0x61, 0xF3, + 0x03, 0x00, 0x84, 0xF8, 0x55, 0x00, 0x04, 0x21, 0x20, 0x46, 0xEB, 0xF7, + 0x78, 0xFB, 0x28, 0x68, + 0x90, 0xF8, 0x4E, 0x01, 0xA0, 0x70, 0x28, 0x68, 0x21, 0x8E, 0xB0, 0xF8, + 0x53, 0x21, 0x62, 0xF3, + 0x08, 0x01, 0x21, 0x86, 0x90, 0xF8, 0x4F, 0x01, 0x00, 0xF0, 0x0F, 0x01, + 0x20, 0x46, 0xEB, 0xF7, + 0xC6, 0xFB, 0x28, 0x68, 0x34, 0xF8, 0x1A, 0x1F, 0xB0, 0xF8, 0x3E, 0x21, + 0x62, 0xF3, 0x0B, 0x01, + 0x24, 0xF8, 0x12, 0x19, 0xB0, 0xF8, 0x3C, 0x21, 0x21, 0x89, 0x62, 0xF3, + 0x0B, 0x01, 0x21, 0x81, + 0xB0, 0xF8, 0x3A, 0x21, 0xA1, 0x88, 0x62, 0xF3, 0x0B, 0x01, 0xA1, 0x80, + 0x90, 0xF8, 0x50, 0x21, + 0xA1, 0x7A, 0x62, 0xF3, 0x01, 0x01, 0xA1, 0x72, 0x90, 0xF8, 0x50, 0x21, + 0x92, 0x08, 0x62, 0xF3, + 0x87, 0x11, 0xA1, 0x72, 0x90, 0xF8, 0x32, 0x11, 0x14, 0xF8, 0x01, 0x2C, + 0x61, 0xF3, 0x00, 0x02, + 0x04, 0xF8, 0x01, 0x2C, 0x90, 0xF8, 0x35, 0x01, 0x60, 0x70, 0x42, 0x48, + 0x90, 0xF8, 0x50, 0x1E, + 0xA1, 0x75, 0x90, 0xF8, 0x51, 0x1E, 0x21, 0x77, 0x90, 0xF8, 0x52, 0x1E, + 0xE1, 0x75, 0x90, 0xF8, + 0x53, 0x1E, 0x61, 0x77, 0x90, 0xF8, 0x54, 0x1E, 0x21, 0x76, 0x90, 0xF8, + 0x55, 0x0E, 0xA0, 0x77, + 0x39, 0x48, 0xEB, 0xF7, 0xF6, 0xFA, 0xA4, 0xF8, 0x78, 0x00, 0x37, 0x48, + 0x20, 0x30, 0xEB, 0xF7, + 0xF0, 0xFA, 0xA4, 0xF8, 0x7C, 0x00, 0x28, 0x68, 0x90, 0xF8, 0x42, 0x11, + 0x0A, 0x09, 0x21, 0x7D, + 0x62, 0xF3, 0x07, 0x11, 0x21, 0x75, 0x90, 0xF8, 0x47, 0x21, 0xA3, 0x7E, + 0x12, 0x09, 0x62, 0xF3, + 0x07, 0x13, 0xA3, 0x76, 0x90, 0xF8, 0x43, 0x61, 0x62, 0x7D, 0x66, 0xF3, + 0x03, 0x02, 0x62, 0x75, + 0x90, 0xF8, 0x48, 0x71, 0xE6, 0x7E, 0x67, 0xF3, 0x03, 0x06, 0xE6, 0x76, + 0x90, 0xF8, 0x43, 0x71, + 0x3F, 0x09, 0x67, 0xF3, 0x07, 0x12, 0x62, 0x75, 0x90, 0xF8, 0x48, 0x21, + 0x12, 0x09, 0x62, 0xF3, + 0x07, 0x16, 0xE6, 0x76, 0x90, 0xF8, 0x42, 0x21, 0x62, 0xF3, 0x00, 0x01, + 0x21, 0x75, 0x90, 0xF8, + 0x47, 0x11, 0x61, 0xF3, 0x00, 0x03, 0xA3, 0x76, 0x90, 0xF8, 0x37, 0x01, + 0x01, 0x09, 0xE0, 0x78, + 0x61, 0xF3, 0x03, 0x00, 0xE0, 0x70, 0x18, 0x48, 0x48, 0x38, 0xEB, 0xF7, + 0xB2, 0xFA, 0xA4, 0xF8, + 0x76, 0x00, 0x15, 0x48, 0x28, 0x38, 0xEB, 0xF7, 0xAC, 0xFA, 0xA4, 0xF8, + 0x7A, 0x00, 0x29, 0x68, + 0x91, 0xF8, 0x34, 0x01, 0xC2, 0x08, 0x14, 0xF8, 0x1F, 0x0F, 0x62, 0xF3, + 0x83, 0x00, 0x20, 0x70, + 0x91, 0xF8, 0x34, 0x21, 0x52, 0x08, 0x62, 0xF3, 0x00, 0x00, 0x20, 0x70, + 0x91, 0xF8, 0x34, 0x21, + 0x92, 0x08, 0x62, 0xF3, 0x41, 0x00, 0x11, 0xE0, 0xD4, 0x07, 0x10, 0x00, + 0x04, 0x7D, 0x01, 0x00, + 0x57, 0x4F, 0x01, 0x00, 0x7A, 0xA3, 0x01, 0x20, 0x6C, 0xA2, 0x01, 0x20, + 0xB4, 0x84, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x78, 0x8B, 0x01, 0x20, 0x80, 0x99, 0x01, 0x20, + 0x04, 0xF8, 0x27, 0x09, + 0x91, 0xF8, 0x33, 0x01, 0xC0, 0xF3, 0x81, 0x01, 0x20, 0x46, 0xEB, 0xF7, + 0xF5, 0xFA, 0x28, 0x68, + 0x90, 0xF8, 0x33, 0x01, 0x01, 0x09, 0x14, 0xF8, 0x28, 0x0F, 0x61, 0xF3, + 0x04, 0x10, 0x20, 0x70, + 0xF8, 0x48, 0xEB, 0xF7, 0x6E, 0xFA, 0xA4, 0xF8, 0x60, 0x00, 0xF6, 0x48, + 0x20, 0x30, 0xEB, 0xF7, + 0x68, 0xFA, 0xA4, 0xF8, 0x62, 0x00, 0x28, 0x68, 0x90, 0xF8, 0x32, 0x11, + 0xCA, 0x08, 0xE1, 0x7A, + 0x62, 0xF3, 0x45, 0x11, 0xE1, 0x72, 0x90, 0xF8, 0x33, 0x01, 0x41, 0x08, + 0x20, 0x78, 0x61, 0xF3, + 0x45, 0x10, 0x04, 0xF8, 0x28, 0x09, 0x20, 0x46, 0x01, 0xF0, 0x50, 0xFC, + 0x28, 0x68, 0x90, 0xF8, + 0x36, 0x01, 0x81, 0x09, 0x20, 0x46, 0xEB, 0xF7, 0xB4, 0xFA, 0x14, 0xF8, + 0x32, 0x0F, 0x20, 0xF0, + 0x0F, 0x00, 0x0A, 0x30, 0x20, 0xF0, 0xF0, 0x00, 0xA0, 0x30, 0x04, 0xF8, + 0x1C, 0x09, 0x29, 0x68, + 0x91, 0xF8, 0x32, 0x01, 0x82, 0x09, 0x60, 0x7F, 0x62, 0xF3, 0x00, 0x00, + 0x60, 0x77, 0x91, 0xF8, + 0x32, 0x21, 0x52, 0x09, 0x62, 0xF3, 0x41, 0x00, 0x60, 0x77, 0x91, 0xF8, + 0x38, 0x21, 0x62, 0xF3, + 0x82, 0x00, 0x60, 0x77, 0x91, 0xF8, 0x51, 0x01, 0xE2, 0x7D, 0x60, 0xF3, + 0x04, 0x02, 0xE2, 0x75, + 0x91, 0xF8, 0x52, 0x01, 0xA1, 0x7D, 0x60, 0xF3, 0x04, 0x01, 0xD3, 0x48, + 0xA1, 0x75, 0x94, 0xF8, + 0x49, 0x10, 0x40, 0x78, 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, 0x49, 0x10, + 0xCF, 0x48, 0xEB, 0xF7, + 0x18, 0xFA, 0xA4, 0xF8, 0x64, 0x00, 0x28, 0x68, 0x21, 0x8B, 0xB0, 0xF8, + 0x40, 0x21, 0x62, 0xF3, + 0x0B, 0x01, 0x21, 0x83, 0x90, 0xF8, 0x36, 0x11, 0xCA, 0x08, 0x94, 0xF8, + 0x22, 0x10, 0x62, 0xF3, + 0x02, 0x01, 0x84, 0xF8, 0x22, 0x10, 0x10, 0xF8, 0xE0, 0x1F, 0x22, 0x7D, + 0x61, 0xF3, 0x03, 0x02, + 0x22, 0x75, 0x10, 0xF8, 0x52, 0x1B, 0x0A, 0x09, 0x61, 0x7D, 0x62, 0xF3, + 0x03, 0x01, 0x61, 0x75, + 0x42, 0x79, 0xE1, 0x7C, 0x62, 0xF3, 0x02, 0x01, 0xE1, 0x74, 0x01, 0x78, + 0xCA, 0x09, 0xA1, 0x7F, + 0x62, 0xF3, 0x00, 0x01, 0xA1, 0x77, 0x94, 0xF8, 0x49, 0x10, 0x41, 0xF0, + 0x20, 0x01, 0x84, 0xF8, + 0x49, 0x10, 0x82, 0x78, 0xD2, 0x09, 0x62, 0xF3, 0xC7, 0x11, 0x84, 0xF8, + 0x49, 0x10, 0x42, 0x8B, + 0xB4, 0xF8, 0x4A, 0x10, 0x62, 0xF3, 0x08, 0x01, 0xA4, 0xF8, 0x4A, 0x10, + 0x00, 0x21, 0xE1, 0x64, + 0x41, 0x79, 0xCA, 0x08, 0x61, 0x7F, 0x62, 0xF3, 0xC3, 0x01, 0x61, 0x77, + 0x02, 0x78, 0x12, 0x09, + 0x62, 0xF3, 0x04, 0x11, 0x61, 0x77, 0xC1, 0x7F, 0x4A, 0x09, 0x14, 0xF8, + 0x0E, 0x1C, 0x62, 0xF3, + 0x06, 0x11, 0x04, 0xF8, 0x0E, 0x1C, 0x41, 0x78, 0x4A, 0x09, 0xA1, 0x78, + 0x62, 0xF3, 0xC3, 0x01, + 0xA1, 0x70, 0x02, 0x78, 0x52, 0x08, 0x62, 0xF3, 0x04, 0x11, 0xA1, 0x70, + 0x82, 0x78, 0x92, 0x09, + 0x62, 0xF3, 0x86, 0x11, 0xA1, 0x70, 0x40, 0x78, 0x9D, 0x49, 0xC0, 0xF3, + 0x80, 0x10, 0x48, 0x71, + 0xBD, 0xE8, 0xF0, 0x81, 0xA4, 0x22, 0x9B, 0x49, 0x01, 0xF0, 0xFF, 0xBD, + 0x2D, 0xE9, 0xF0, 0x41, + 0x97, 0x4D, 0x00, 0x26, 0x01, 0x27, 0x2E, 0x71, 0x2E, 0x72, 0xAF, 0x71, + 0x0C, 0x46, 0x6E, 0x72, + 0x01, 0x28, 0x07, 0xD0, 0x90, 0x4F, 0x02, 0x28, 0x2C, 0xD0, 0x03, 0x28, + 0x14, 0xD0, 0x04, 0x28, + 0x3A, 0xD1, 0x43, 0xE0, 0x08, 0x46, 0xFF, 0xF7, 0xE5, 0xFF, 0x8F, 0x48, + 0x01, 0x68, 0x91, 0xF8, + 0x38, 0x01, 0x42, 0x06, 0x30, 0xD5, 0x91, 0xF8, 0x55, 0x11, 0x00, 0x06, + 0x01, 0xF0, 0x03, 0x01, + 0x29, 0x72, 0x29, 0xD5, 0x6F, 0x72, 0x27, 0xE0, 0x86, 0x48, 0xFF, 0xF7, + 0x08, 0xFE, 0x20, 0x46, + 0xFF, 0xF7, 0xD0, 0xFF, 0xF8, 0x78, 0x94, 0xF8, 0x5F, 0x10, 0x60, 0xF3, + 0x04, 0x01, 0x84, 0xF8, + 0x5F, 0x10, 0x94, 0xF8, 0x27, 0x00, 0x20, 0xF0, 0x02, 0x00, 0x40, 0xF0, + 0x01, 0x00, 0x84, 0xF8, + 0x27, 0x00, 0x0C, 0xE0, 0x7B, 0x48, 0xFF, 0xF7, 0xF2, 0xFD, 0x20, 0x46, + 0xFF, 0xF7, 0xBA, 0xFF, + 0xB8, 0x78, 0x94, 0xF8, 0x5F, 0x10, 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, + 0x5F, 0x10, 0x00, 0x21, + 0x20, 0x46, 0xEB, 0xF7, 0xEC, 0xF9, 0xAE, 0x71, 0x20, 0x46, 0x01, 0xF0, + 0xD7, 0xFB, 0x94, 0xF8, + 0x27, 0x00, 0x40, 0xF3, 0x00, 0x00, 0x40, 0x1C, 0xE8, 0x71, 0xA1, 0xE7, + 0x08, 0x46, 0xFF, 0xF7, + 0xA1, 0xFF, 0x14, 0xF8, 0x37, 0x0F, 0x40, 0xF0, 0x10, 0x00, 0x04, 0xF8, + 0x1F, 0x09, 0xE0, 0x7E, + 0x20, 0xF0, 0x23, 0x00, 0xE0, 0x76, 0x34, 0xF8, 0x0C, 0x0C, 0x6F, 0xF3, + 0x0B, 0x00, 0x10, 0x30, + 0x24, 0xF8, 0x0C, 0x0C, 0x34, 0xF8, 0x08, 0x0C, 0x6F, 0xF3, 0x0B, 0x00, + 0x40, 0x30, 0x24, 0xF8, + 0x08, 0x0C, 0x08, 0x20, 0x04, 0xF8, 0x16, 0x0C, 0x94, 0xF8, 0x47, 0x00, + 0x20, 0xF0, 0x1F, 0x00, + 0x84, 0xF8, 0x47, 0x00, 0x34, 0xF8, 0x18, 0x0F, 0x6F, 0xF3, 0x08, 0x00, + 0x24, 0xF8, 0x03, 0x0B, + 0x20, 0x78, 0x40, 0xF0, 0x0C, 0x00, 0x04, 0xF8, 0x0B, 0x09, 0x20, 0x78, + 0x40, 0xF0, 0x20, 0x00, + 0x04, 0xF8, 0x28, 0x09, 0xBF, 0xE7, 0x70, 0xB5, 0x53, 0x4D, 0x28, 0x68, + 0x00, 0xF2, 0x5E, 0x62, + 0x00, 0xF6, 0x6E, 0x04, 0x90, 0xF8, 0x56, 0x16, 0x90, 0xF8, 0x57, 0x06, + 0x02, 0xEB, 0x40, 0x00, + 0x01, 0xF0, 0xA5, 0xFA, 0x28, 0x68, 0x90, 0xF8, 0x66, 0x18, 0x90, 0xF8, + 0x67, 0x08, 0x04, 0xEB, + 0x40, 0x00, 0xBD, 0xE8, 0x70, 0x40, 0x01, 0xF0, 0xB1, 0xBA, 0x70, 0xB5, + 0x44, 0x4D, 0x45, 0x4C, + 0x68, 0x79, 0xA4, 0x34, 0x00, 0xB1, 0x02, 0x20, 0x68, 0x70, 0x21, 0x46, + 0x28, 0x78, 0xFF, 0xF7, + 0x4D, 0xFF, 0x41, 0x48, 0x01, 0x68, 0xA0, 0x7C, 0x91, 0xF8, 0x50, 0x21, + 0x62, 0xF3, 0x01, 0x00, + 0xA0, 0x74, 0x91, 0xF8, 0x50, 0x11, 0x89, 0x08, 0x61, 0xF3, 0x87, 0x10, + 0xA0, 0x74, 0x69, 0x78, + 0x20, 0x46, 0xEB, 0xF7, 0x93, 0xFB, 0xA0, 0x7C, 0x00, 0xF0, 0x03, 0x00, + 0x01, 0xF0, 0xA6, 0xFA, + 0xFF, 0xF7, 0xC1, 0xFF, 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x34, 0x49, + 0xEB, 0xF7, 0xBB, 0xBB, + 0x70, 0xB5, 0x2F, 0x4D, 0x2F, 0x4C, 0x68, 0x79, 0xA4, 0x34, 0x08, 0xB1, + 0x03, 0x20, 0x00, 0xE0, + 0x01, 0x20, 0x68, 0x70, 0x21, 0x46, 0x28, 0x78, 0xFF, 0xF7, 0x20, 0xFF, + 0x2A, 0x48, 0x01, 0x68, + 0x91, 0xF8, 0x50, 0x01, 0x02, 0x09, 0xA0, 0x7C, 0x62, 0xF3, 0x01, 0x00, + 0xA0, 0x74, 0x91, 0xF8, + 0x50, 0x11, 0x89, 0x09, 0x61, 0xF3, 0x87, 0x10, 0xA0, 0x74, 0x69, 0x78, + 0x20, 0x46, 0xEB, 0xF7, + 0x65, 0xFB, 0xA0, 0x7C, 0x00, 0xF0, 0x03, 0x00, 0x01, 0xF0, 0x78, 0xFA, + 0xFF, 0xF7, 0x93, 0xFF, + 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, 0x1E, 0x49, 0xEB, 0xF7, 0x8D, 0xBB, + 0x7F, 0xB5, 0x01, 0xF0, + 0xFB, 0xF9, 0x01, 0x90, 0x01, 0xF0, 0xFC, 0xF9, 0xCD, 0xE9, 0x02, 0x01, + 0x04, 0x21, 0x01, 0xA8, + 0xEB, 0xF7, 0x49, 0xFD, 0x12, 0x4C, 0x08, 0x21, 0xA0, 0x70, 0x02, 0xA8, + 0xEB, 0xF7, 0x43, 0xFD, + 0xE0, 0x70, 0x0D, 0x4D, 0x01, 0x24, 0xE0, 0xB2, 0xFF, 0xF7, 0xC1, 0xFC, + 0x28, 0x55, 0x64, 0x1C, + 0x05, 0x2C, 0xF8, 0xDB, 0x0B, 0x48, 0xFF, 0xF7, 0x12, 0xFD, 0x7F, 0xBD, + 0x10, 0xB5, 0x80, 0x79, + 0xC0, 0xB1, 0x07, 0x49, 0x08, 0x70, 0x4F, 0xF0, 0xFF, 0x30, 0xC8, 0x60, + 0xFF, 0xF7, 0xEE, 0xFB, + 0x00, 0x20, 0x10, 0xBD, 0x48, 0xBF, 0x01, 0x20, 0x64, 0xA2, 0x01, 0x20, + 0x00, 0x9B, 0x01, 0x20, + 0xD4, 0x07, 0x10, 0x00, 0xCC, 0x80, 0x10, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x93, 0x4F, 0x01, 0x00, + 0x29, 0x50, 0x01, 0x00, 0x01, 0x20, 0xEC, 0xE7, 0x2D, 0xE9, 0xF0, 0x47, + 0xF9, 0x49, 0x02, 0x46, + 0x01, 0x27, 0x08, 0x68, 0xB8, 0x46, 0x00, 0xF2, 0x5E, 0x64, 0x02, 0x2A, + 0x01, 0xD0, 0x03, 0x2A, + 0x3C, 0xD0, 0x89, 0x46, 0x90, 0xF8, 0x23, 0x11, 0x90, 0xF8, 0x1F, 0x61, + 0x01, 0xF0, 0x1F, 0x05, + 0x90, 0xF8, 0x12, 0x11, 0x89, 0x06, 0x09, 0xD5, 0x90, 0xF8, 0x5A, 0x16, + 0x90, 0xF8, 0x5B, 0x06, + 0x0A, 0x22, 0x04, 0xEB, 0x40, 0x00, 0x01, 0xF0, 0xBF, 0xF9, 0x07, 0x46, + 0xD9, 0xF8, 0x00, 0x00, + 0x90, 0xF8, 0x12, 0x11, 0x49, 0x06, 0x09, 0xD5, 0x90, 0xF8, 0x6A, 0x18, + 0x90, 0xF8, 0x6B, 0x08, + 0x0A, 0x22, 0x04, 0xEB, 0x40, 0x00, 0x01, 0xF0, 0xAF, 0xF9, 0x80, 0x46, + 0x4F, 0xF4, 0x80, 0x70, + 0x86, 0x42, 0x00, 0xD9, 0x06, 0x46, 0x1F, 0x2D, 0x00, 0xD9, 0x1F, 0x25, + 0x6D, 0x1C, 0x6E, 0x43, + 0x70, 0x00, 0xC0, 0xEB, 0x40, 0x20, 0x78, 0x43, 0x00, 0xFB, 0x08, 0xF0, + 0xC0, 0x13, 0xB0, 0xFA, + 0x80, 0xF0, 0xC0, 0xF1, 0x20, 0x00, 0xC0, 0xB2, 0xBD, 0xE8, 0xF0, 0x87, + 0x10, 0xF8, 0xD3, 0x6F, + 0x00, 0x79, 0x00, 0xF0, 0x1F, 0x05, 0xE1, 0xE7, 0x70, 0xB5, 0x05, 0x00, + 0x03, 0xD0, 0xBD, 0xE8, + 0x70, 0x40, 0x01, 0xF0, 0x1A, 0xB9, 0xD0, 0x48, 0xD0, 0x4E, 0x00, 0x78, + 0x01, 0x28, 0x01, 0xD0, + 0xCF, 0x48, 0x16, 0xE0, 0xCB, 0x4C, 0xCE, 0x49, 0x22, 0x68, 0xA1, 0xF1, + 0x08, 0x00, 0x02, 0xF2, + 0x72, 0x42, 0x00, 0xF0, 0xD1, 0xF9, 0x22, 0x68, 0x92, 0xF8, 0x60, 0x04, + 0xC0, 0x07, 0x06, 0xD0, + 0xC7, 0x49, 0x02, 0xF2, 0x76, 0x42, 0xA1, 0xF1, 0x08, 0x00, 0x00, 0xF0, + 0xC5, 0xF9, 0xC4, 0x48, + 0x08, 0x38, 0x70, 0x61, 0x28, 0x46, 0xDA, 0xE7, 0x70, 0xB5, 0x04, 0x46, + 0xEA, 0xF7, 0xEC, 0xFF, + 0xBF, 0x48, 0xEA, 0xF7, 0xEE, 0xFF, 0xA4, 0xF8, 0x76, 0x00, 0x01, 0xF0, + 0x3D, 0xF9, 0x01, 0x46, + 0x00, 0x22, 0x20, 0x46, 0xEB, 0xF7, 0x88, 0xF9, 0x01, 0xF0, 0x3A, 0xF9, + 0x02, 0x46, 0x0B, 0x46, + 0x20, 0x46, 0xEB, 0xF7, 0xAD, 0xF9, 0xA0, 0x79, 0x00, 0x21, 0x20, 0xF0, + 0x02, 0x00, 0xA0, 0x71, + 0x94, 0xF8, 0x6F, 0x00, 0x20, 0xF0, 0x07, 0x00, 0x84, 0xF8, 0x6F, 0x00, + 0x94, 0xF8, 0x6E, 0x00, + 0x20, 0xF0, 0x0F, 0x00, 0x84, 0xF8, 0x6E, 0x00, 0x20, 0x46, 0xEB, 0xF7, + 0xB3, 0xF9, 0x94, 0xF8, + 0x5E, 0x00, 0x20, 0xF0, 0x01, 0x00, 0x84, 0xF8, 0x5E, 0x00, 0x20, 0x46, + 0x01, 0xF0, 0x52, 0xFA, + 0x04, 0x21, 0x20, 0x46, 0xEA, 0xF7, 0xEB, 0xFF, 0xA2, 0x4D, 0x28, 0x68, + 0x90, 0xF8, 0x1F, 0x01, + 0xA0, 0x70, 0x28, 0x68, 0x21, 0x8E, 0xB0, 0xF8, 0x24, 0x21, 0x62, 0xF3, + 0x08, 0x01, 0x21, 0x86, + 0x90, 0xF8, 0x20, 0x01, 0x00, 0xF0, 0x0F, 0x01, 0x20, 0x46, 0xEB, 0xF7, + 0x38, 0xF8, 0x28, 0x68, + 0x62, 0x7D, 0x90, 0xF8, 0x16, 0x11, 0x61, 0xF3, 0x03, 0x02, 0x62, 0x75, + 0xB0, 0xF8, 0x19, 0x21, + 0x21, 0x8A, 0x62, 0xF3, 0x0B, 0x01, 0x21, 0x82, 0x90, 0xF8, 0x21, 0x11, + 0xA2, 0x7D, 0x61, 0xF3, + 0x03, 0x02, 0xA2, 0x75, 0xB0, 0xF8, 0x1B, 0x21, 0xA1, 0x89, 0x62, 0xF3, + 0x0B, 0x01, 0xA1, 0x81, + 0x90, 0xF8, 0x20, 0x11, 0x0A, 0x09, 0xA1, 0x7C, 0x62, 0xF3, 0x01, 0x01, + 0xA1, 0x74, 0x90, 0xF8, + 0x20, 0x21, 0x92, 0x09, 0x62, 0xF3, 0x87, 0x11, 0xA1, 0x74, 0x90, 0xF8, + 0x12, 0x11, 0xE2, 0x79, + 0x61, 0xF3, 0x00, 0x02, 0xE2, 0x71, 0x90, 0xF8, 0x15, 0x11, 0x61, 0x72, + 0x90, 0xF8, 0x18, 0x01, + 0x01, 0x09, 0xE0, 0x7A, 0x61, 0xF3, 0x03, 0x00, 0xE0, 0x72, 0x82, 0x48, + 0xEA, 0xF7, 0x71, 0xFF, + 0xA4, 0xF8, 0x7C, 0x00, 0x29, 0x68, 0x91, 0xF8, 0x14, 0x01, 0xC2, 0x08, + 0x94, 0xF8, 0x27, 0x00, + 0x62, 0xF3, 0x83, 0x00, 0x20, 0xF0, 0x02, 0x00, 0x40, 0xF0, 0x01, 0x00, + 0x84, 0xF8, 0x27, 0x00, + 0x91, 0xF8, 0x13, 0x01, 0xC0, 0xF3, 0x81, 0x01, 0x20, 0x46, 0xEA, 0xF7, + 0xD5, 0xFF, 0x28, 0x68, + 0x90, 0xF8, 0x13, 0x01, 0x01, 0x09, 0x14, 0xF8, 0x28, 0x0F, 0x61, 0xF3, + 0x04, 0x10, 0x20, 0x70, + 0x71, 0x48, 0xEA, 0xF7, 0x4E, 0xFF, 0xA4, 0xF8, 0x5E, 0x00, 0x28, 0x68, + 0x90, 0xF8, 0x12, 0x11, + 0xCA, 0x08, 0xE1, 0x7A, 0x62, 0xF3, 0x45, 0x11, 0xE1, 0x72, 0x90, 0xF8, + 0x13, 0x01, 0x41, 0x08, + 0x20, 0x78, 0x61, 0xF3, 0x45, 0x10, 0x04, 0xF8, 0x28, 0x09, 0x20, 0x46, + 0x01, 0xF0, 0x10, 0xF9, + 0x28, 0x68, 0x90, 0xF8, 0x18, 0x01, 0xC0, 0xF3, 0x81, 0x01, 0x20, 0x46, + 0xEA, 0xF7, 0x99, 0xFF, + 0x14, 0xF8, 0x32, 0x0F, 0x20, 0xF0, 0x0F, 0x00, 0x0A, 0x30, 0x20, 0xF0, + 0xF0, 0x00, 0xA0, 0x30, + 0x04, 0xF8, 0x0A, 0x09, 0x29, 0x68, 0x91, 0xF8, 0x12, 0x01, 0x82, 0x09, + 0xE0, 0x7A, 0x62, 0xF3, + 0x00, 0x00, 0xE0, 0x72, 0x91, 0xF8, 0x12, 0x21, 0x52, 0x09, 0x62, 0xF3, + 0x41, 0x00, 0xE0, 0x72, + 0x91, 0xF8, 0x17, 0x21, 0xD2, 0x09, 0x62, 0xF3, 0x82, 0x00, 0xE0, 0x72, + 0x91, 0xF8, 0x22, 0x01, + 0x62, 0x79, 0x60, 0xF3, 0x04, 0x02, 0x62, 0x71, 0x91, 0xF8, 0x23, 0x01, + 0x21, 0x79, 0x60, 0xF3, + 0x04, 0x01, 0x4B, 0x48, 0x21, 0x71, 0x0C, 0x38, 0x41, 0x78, 0x94, 0xF8, + 0x37, 0x00, 0x61, 0xF3, + 0x04, 0x00, 0x84, 0xF8, 0x37, 0x00, 0x49, 0x48, 0xEA, 0xF7, 0xFB, 0xFE, + 0xA4, 0xF8, 0x52, 0x00, + 0x28, 0x68, 0xE1, 0x88, 0xB0, 0xF8, 0x1D, 0x21, 0x62, 0xF3, 0x0B, 0x01, + 0xE1, 0x80, 0x90, 0xF8, + 0x17, 0x11, 0xCA, 0x08, 0x21, 0x7C, 0x62, 0xF3, 0x02, 0x01, 0x21, 0x74, + 0x10, 0xF8, 0xDF, 0x2F, + 0xA1, 0x78, 0x62, 0xF3, 0x03, 0x01, 0xA1, 0x70, 0x10, 0xF8, 0x19, 0x1B, + 0x0A, 0x09, 0xE1, 0x78, + 0x62, 0xF3, 0x03, 0x01, 0xE1, 0x70, 0x81, 0x7F, 0x0A, 0x09, 0x61, 0x78, + 0x62, 0xF3, 0x02, 0x01, + 0x61, 0x70, 0x01, 0x7F, 0x8A, 0x09, 0x21, 0x78, 0x62, 0xF3, 0x00, 0x01, + 0x21, 0x70, 0x81, 0x7E, + 0xCA, 0x09, 0x21, 0x7B, 0x62, 0xF3, 0x00, 0x01, 0x21, 0x73, 0x94, 0xF8, + 0x37, 0x10, 0x41, 0xF0, + 0x20, 0x01, 0x84, 0xF8, 0x37, 0x10, 0x21, 0x8F, 0x6F, 0xF3, 0x08, 0x01, + 0x01, 0xF5, 0x80, 0x71, + 0x21, 0x87, 0x00, 0x21, 0xC4, 0xF8, 0x3A, 0x10, 0xC1, 0x7F, 0x8A, 0x09, + 0xE1, 0x7A, 0x62, 0xF3, + 0xC3, 0x01, 0xE1, 0x72, 0x80, 0x7E, 0x00, 0x09, 0x60, 0xF3, 0x04, 0x11, + 0xE1, 0x72, 0x70, 0xBD, + 0x70, 0xB5, 0x1F, 0x4D, 0x00, 0x20, 0x0C, 0x3D, 0x01, 0x24, 0x28, 0x60, + 0xE0, 0xB2, 0xFF, 0xF7, + 0x3B, 0xFE, 0x28, 0x55, 0x64, 0x1C, 0x04, 0x2C, 0xF8, 0xDB, 0xBD, 0xE8, + 0x70, 0x40, 0x1C, 0x48, + 0xAA, 0xE6, 0x70, 0xB5, 0x41, 0x7A, 0xAA, 0xB0, 0x59, 0xB1, 0x13, 0x4D, + 0x01, 0x20, 0x6C, 0x46, + 0x28, 0x70, 0x01, 0x29, 0x08, 0xD0, 0x00, 0x26, 0x02, 0x29, 0x09, 0xD0, + 0x03, 0x29, 0x2D, 0xD1, + 0x28, 0xE0, 0x01, 0x20, 0x2A, 0xB0, 0x70, 0xBD, 0x20, 0x46, 0x00, 0xF0, + 0x60, 0xF8, 0x25, 0xE0, + 0x20, 0x46, 0x00, 0xF0, 0x5C, 0xF8, 0x0A, 0x48, 0x9D, 0xF8, 0x5F, 0x10, + 0x0C, 0x38, 0x80, 0x78, + 0x60, 0xF3, 0x04, 0x01, 0x8D, 0xF8, 0x5F, 0x10, 0x00, 0x21, 0x20, 0x46, + 0xEA, 0xF7, 0x07, 0xFF, + 0x13, 0xE0, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, 0xE4, 0x07, 0x10, 0x00, + 0xB4, 0x84, 0x10, 0x00, + 0xC0, 0xA4, 0x01, 0x20, 0x98, 0x98, 0x01, 0x20, 0x20, 0xBF, 0x01, 0x20, + 0x00, 0x9B, 0x01, 0x20, + 0x14, 0x82, 0x10, 0x00, 0x20, 0x46, 0x00, 0xF0, 0x3E, 0xF8, 0x2E, 0x70, + 0x20, 0x46, 0x01, 0xF0, + 0xDD, 0xF8, 0x9D, 0xF8, 0x12, 0x00, 0x00, 0xF0, 0x03, 0x00, 0x01, 0xF0, + 0x1F, 0xF8, 0x37, 0x4C, + 0x20, 0x68, 0x00, 0xF2, 0x5E, 0x63, 0x00, 0xF6, 0x6E, 0x05, 0x90, 0xF8, + 0x5A, 0x16, 0x90, 0xF8, + 0x5B, 0x06, 0x03, 0xEB, 0x40, 0x00, 0x00, 0xF0, 0xE2, 0xFF, 0x20, 0x68, + 0x90, 0xF8, 0x6A, 0x18, + 0x90, 0xF8, 0x6B, 0x08, 0x05, 0xEB, 0x40, 0x00, 0x00, 0xF0, 0xF0, 0xFF, + 0x2C, 0x49, 0x68, 0x46, + 0xEB, 0xF7, 0x34, 0xF8, 0x00, 0x20, 0xAD, 0xE7, 0x40, 0xF2, 0xFF, 0x10, + 0xC1, 0xEB, 0x41, 0x21, + 0x91, 0xFB, 0xF0, 0xF0, 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0x00, 0x23, + 0xD4, 0x5C, 0x31, 0xF8, + 0x14, 0x40, 0x20, 0xF8, 0x13, 0x40, 0x5B, 0x1C, 0x04, 0x2B, 0xF7, 0xDB, + 0x10, 0xBD, 0xA4, 0x22, + 0x20, 0x49, 0x01, 0xF0, 0x7A, 0xBA, 0x70, 0xB5, 0x04, 0x46, 0x00, 0xF0, + 0x6A, 0xFB, 0x1E, 0x48, + 0xEA, 0xF7, 0x1F, 0xFE, 0xA4, 0xF8, 0x76, 0x00, 0x00, 0xF0, 0x77, 0xFF, + 0x17, 0x4D, 0x01, 0x46, + 0x28, 0x68, 0x90, 0xF8, 0xC9, 0x00, 0xC0, 0xF3, 0x41, 0x12, 0x20, 0x46, + 0xEA, 0xF7, 0xB4, 0xFF, + 0x00, 0xF0, 0x70, 0xFF, 0x02, 0x46, 0x0B, 0x46, 0x20, 0x46, 0xEA, 0xF7, + 0xD9, 0xFF, 0x13, 0x48, + 0xEA, 0xF7, 0x07, 0xFE, 0xA4, 0xF8, 0x7C, 0x00, 0x0F, 0x48, 0x0C, 0x38, + 0xC1, 0x78, 0x14, 0xF8, + 0x5F, 0x0F, 0x61, 0xF3, 0x04, 0x00, 0x20, 0x70, 0x29, 0x68, 0x00, 0xF0, + 0x1F, 0x00, 0x11, 0xF8, + 0xD3, 0x2F, 0xC9, 0x78, 0x01, 0xF0, 0x1F, 0x01, 0x49, 0x1C, 0xC1, 0xEB, + 0x41, 0x21, 0x49, 0x00, + 0x4A, 0x43, 0xC2, 0x40, 0x50, 0x08, 0xC4, 0xF8, 0x03, 0x00, 0x70, 0xBD, + 0x4C, 0x07, 0x10, 0x00, + 0x29, 0x58, 0x01, 0x00, 0x14, 0x82, 0x10, 0x00, 0xC0, 0xA4, 0x01, 0x20, + 0x98, 0x98, 0x01, 0x20, + 0x10, 0xB9, 0x66, 0x4A, 0x64, 0x49, 0x11, 0x61, 0x00, 0xF0, 0xDF, 0xBE, + 0x70, 0xB5, 0x64, 0x4D, + 0x04, 0x46, 0x28, 0x68, 0x90, 0xF8, 0xF1, 0x01, 0xC0, 0xF3, 0x01, 0x12, + 0xC0, 0xF3, 0x81, 0x01, + 0x00, 0xF0, 0x03, 0x00, 0xFD, 0xF7, 0xA1, 0xFA, 0x40, 0x1C, 0xC6, 0xB2, + 0x20, 0x46, 0x00, 0xF0, + 0x71, 0xFC, 0x59, 0x48, 0xEA, 0xF7, 0xC5, 0xFD, 0xA4, 0xF8, 0x76, 0x00, + 0x00, 0x22, 0x31, 0x46, + 0x20, 0x46, 0xEA, 0xF7, 0x82, 0xFF, 0xA0, 0x79, 0x40, 0xF0, 0x02, 0x00, + 0xA0, 0x71, 0x94, 0xF8, + 0x6F, 0x00, 0x66, 0xF3, 0x02, 0x00, 0x84, 0xF8, 0x6F, 0x00, 0x94, 0xF8, + 0x6E, 0x00, 0x20, 0xF0, + 0x0F, 0x00, 0x84, 0xF8, 0x6E, 0x00, 0x29, 0x68, 0xA0, 0x7C, 0x91, 0xF8, + 0x08, 0x21, 0x62, 0xF3, + 0x01, 0x00, 0xA0, 0x74, 0x91, 0xF8, 0x08, 0x21, 0x92, 0x08, 0x62, 0xF3, + 0x87, 0x10, 0xA0, 0x74, + 0xA0, 0x89, 0x6F, 0xF3, 0x0B, 0x00, 0xA0, 0x81, 0x91, 0xF8, 0x07, 0x01, + 0xA0, 0x70, 0x94, 0xF8, + 0x5E, 0x00, 0x00, 0x21, 0x20, 0xF0, 0x01, 0x00, 0x84, 0xF8, 0x5E, 0x00, + 0x20, 0x46, 0xEA, 0xF7, + 0x1E, 0xFE, 0x28, 0x68, 0x90, 0xF8, 0xF2, 0x11, 0x84, 0xF8, 0x66, 0x10, + 0x90, 0xF8, 0xF3, 0x11, + 0x84, 0xF8, 0x68, 0x10, 0x90, 0xF8, 0xF4, 0x11, 0x84, 0xF8, 0x6A, 0x10, + 0x90, 0xF8, 0xF5, 0x01, + 0x84, 0xF8, 0x6C, 0x00, 0x34, 0x48, 0x94, 0xF8, 0x5F, 0x10, 0x00, 0x1F, + 0x40, 0x78, 0x60, 0xF3, + 0x04, 0x01, 0x84, 0xF8, 0x5F, 0x10, 0x20, 0x46, 0xBD, 0xE8, 0x70, 0x40, + 0x00, 0xF0, 0x48, 0xBF, + 0x10, 0xB5, 0x2D, 0x4C, 0x00, 0x20, 0x24, 0x1F, 0x20, 0x80, 0x01, 0x20, + 0x00, 0xF0, 0x32, 0xF8, + 0x60, 0x70, 0xBD, 0xE8, 0x10, 0x40, 0x2B, 0x48, 0x88, 0xE7, 0x2D, 0xE9, + 0xF0, 0x41, 0x29, 0x4E, + 0x40, 0x79, 0x28, 0xB3, 0x30, 0x46, 0x00, 0xF0, 0xD9, 0xFF, 0xB0, 0x7C, + 0x00, 0xF0, 0x03, 0x00, + 0x00, 0xF0, 0x1C, 0xFF, 0x22, 0x4F, 0x3C, 0x68, 0x04, 0xF2, 0x5E, 0x60, + 0x94, 0xF8, 0x51, 0x26, + 0x04, 0xF6, 0x6E, 0x05, 0x94, 0xF8, 0x50, 0x16, 0x00, 0xEB, 0x42, 0x00, + 0x00, 0xF0, 0xDF, 0xFE, + 0x38, 0x68, 0x90, 0xF8, 0x60, 0x18, 0x90, 0xF8, 0x61, 0x08, 0x05, 0xEB, + 0x40, 0x00, 0x00, 0xF0, + 0xED, 0xFE, 0x19, 0x49, 0x30, 0x46, 0xEA, 0xF7, 0x31, 0xFF, 0x00, 0x20, + 0xBD, 0xE8, 0xF0, 0x81, + 0x01, 0x20, 0xFB, 0xE7, 0x12, 0x48, 0x4F, 0xF4, 0x80, 0x73, 0x02, 0x68, + 0x92, 0xF8, 0xF5, 0x10, + 0x92, 0xF8, 0x07, 0x01, 0x92, 0xF8, 0xF2, 0x20, 0x01, 0xF0, 0x1F, 0x01, + 0x02, 0xF0, 0x0F, 0x02, + 0x98, 0x42, 0x00, 0xD9, 0x18, 0x46, 0x1F, 0x29, 0x00, 0xD9, 0x1F, 0x21, + 0x49, 0x1C, 0x48, 0x43, + 0x40, 0x00, 0x52, 0x1C, 0x50, 0x43, 0xC0, 0xEB, 0x40, 0x20, 0xC0, 0x13, + 0xB0, 0xFA, 0x80, 0xF0, + 0xC0, 0xF1, 0x20, 0x00, 0xC0, 0xB2, 0x70, 0x47, 0xE4, 0xA4, 0x01, 0x20, + 0xB4, 0x84, 0x10, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0xB8, 0x82, 0x10, 0x00, 0xA1, 0x5C, 0x01, 0x00, + 0x2D, 0xE9, 0xF0, 0x47, + 0xFE, 0x49, 0x4F, 0xF0, 0x01, 0x08, 0x00, 0x27, 0x0A, 0x68, 0x80, 0x1E, + 0x02, 0xF2, 0x5E, 0x64, + 0xC1, 0x46, 0x06, 0x28, 0x52, 0xD2, 0xDF, 0xE8, 0x00, 0xF0, 0x51, 0x09, + 0x2D, 0x51, 0x2D, 0x03, + 0x12, 0xF8, 0xD3, 0x6F, 0x10, 0x79, 0x00, 0xF0, 0x1F, 0x05, 0x70, 0xE0, + 0x92, 0xF8, 0xF5, 0x00, + 0x92, 0xF8, 0x01, 0x61, 0x00, 0xF0, 0x1F, 0x05, 0x92, 0xF8, 0xF2, 0x00, + 0x8A, 0x46, 0x00, 0xF0, + 0x0F, 0x07, 0x92, 0xF8, 0xE6, 0x00, 0x80, 0x06, 0x09, 0xD5, 0x92, 0xF8, + 0x53, 0x06, 0x92, 0xF8, + 0x52, 0x16, 0x04, 0xEB, 0x40, 0x00, 0x0A, 0x22, 0x00, 0xF0, 0x4E, 0xFE, + 0x80, 0x46, 0xDA, 0xF8, + 0x00, 0x00, 0x90, 0xF8, 0xE6, 0x10, 0x49, 0x06, 0x51, 0xD5, 0x90, 0xF8, + 0x62, 0x18, 0x90, 0xF8, + 0x63, 0x08, 0x46, 0xE0, 0x92, 0xF8, 0xFC, 0x00, 0x92, 0xF8, 0xF8, 0x60, + 0x00, 0xF0, 0x1F, 0x05, + 0x92, 0xF8, 0xF9, 0x00, 0x8A, 0x46, 0x00, 0xF0, 0x0F, 0x07, 0x92, 0xF8, + 0xE6, 0x00, 0x80, 0x06, + 0x09, 0xD5, 0x92, 0xF8, 0x55, 0x06, 0x92, 0xF8, 0x54, 0x16, 0x04, 0xEB, + 0x40, 0x00, 0x0A, 0x22, + 0x00, 0xF0, 0x2A, 0xFE, 0x80, 0x46, 0xDA, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0xE6, 0x10, 0x49, 0x06, + 0x2D, 0xD5, 0x90, 0xF8, 0x64, 0x18, 0x90, 0xF8, 0x65, 0x08, 0x22, 0xE0, + 0x92, 0xF8, 0xF5, 0x00, + 0x92, 0xF8, 0xF1, 0x60, 0x00, 0xF0, 0x1F, 0x05, 0x92, 0xF8, 0xF2, 0x00, + 0x8A, 0x46, 0x00, 0xF0, + 0x0F, 0x07, 0x92, 0xF8, 0xE6, 0x00, 0x80, 0x06, 0x09, 0xD5, 0x92, 0xF8, + 0x51, 0x06, 0x92, 0xF8, + 0x50, 0x16, 0x04, 0xEB, 0x40, 0x00, 0x0A, 0x22, 0x00, 0xF0, 0x06, 0xFE, + 0x80, 0x46, 0xDA, 0xF8, + 0x00, 0x00, 0x90, 0xF8, 0xE6, 0x10, 0x49, 0x06, 0x09, 0xD5, 0x90, 0xF8, + 0x60, 0x18, 0x90, 0xF8, + 0x61, 0x08, 0x0A, 0x22, 0x04, 0xEB, 0x40, 0x00, 0x00, 0xF0, 0xF6, 0xFD, + 0x81, 0x46, 0x4F, 0xF4, + 0x80, 0x70, 0x86, 0x42, 0x00, 0xD9, 0x06, 0x46, 0x1F, 0x2D, 0x00, 0xD9, + 0x1F, 0x25, 0x6D, 0x1C, + 0x6E, 0x43, 0x70, 0x00, 0x7F, 0x1C, 0x78, 0x43, 0xC0, 0xEB, 0x40, 0x20, + 0x00, 0xFB, 0x08, 0xF0, + 0x00, 0xFB, 0x09, 0xF0, 0xC0, 0x13, 0xB0, 0xFA, 0x80, 0xF0, 0xC0, 0xF1, + 0x20, 0x00, 0xC0, 0xB2, + 0xBD, 0xE8, 0xF0, 0x87, 0x70, 0xB5, 0x06, 0x00, 0x03, 0xD0, 0xBD, 0xE8, + 0x70, 0x40, 0x00, 0xF0, + 0x64, 0xBD, 0x00, 0xF0, 0x18, 0xF8, 0x01, 0x28, 0x14, 0xD1, 0xA9, 0x4D, + 0xA9, 0x4C, 0x28, 0x78, + 0x01, 0x28, 0x09, 0xD0, 0xA8, 0x48, 0xA0, 0x60, 0x68, 0x78, 0xE0, 0x73, + 0xE8, 0x78, 0xA0, 0x73, + 0xE8, 0x88, 0xA0, 0x81, 0x30, 0x46, 0xE8, 0xE7, 0x6A, 0x79, 0x29, 0x79, + 0xA2, 0x48, 0x00, 0xF0, + 0xB6, 0xFE, 0xF0, 0xE7, 0x70, 0xBD, 0x9E, 0x4B, 0x10, 0xB5, 0xD9, 0x78, + 0x9F, 0x4C, 0x49, 0x1C, + 0xCA, 0xB2, 0xDA, 0x70, 0x99, 0x78, 0x01, 0x20, 0x8A, 0x42, 0x1B, 0xD8, + 0x19, 0x79, 0x58, 0x79, + 0x41, 0x43, 0x99, 0x48, 0xFD, 0xF7, 0xA9, 0xF9, 0xEA, 0xF7, 0x33, 0xFC, + 0xA4, 0xF8, 0x76, 0x00, + 0x92, 0x48, 0x00, 0x68, 0x90, 0xF8, 0xB0, 0x00, 0xC0, 0x07, 0x06, 0xD0, + 0x94, 0xF8, 0x4D, 0x00, + 0x20, 0xF0, 0x03, 0x00, 0x80, 0x1C, 0x84, 0xF8, 0x4D, 0x00, 0x91, 0x49, + 0x20, 0x46, 0xEA, 0xF7, + 0x15, 0xFE, 0x00, 0x20, 0x10, 0xBD, 0x70, 0xB5, 0x04, 0x46, 0xEA, 0xF7, + 0x15, 0xFC, 0x8A, 0x48, + 0xEA, 0xF7, 0x17, 0xFC, 0xA4, 0xF8, 0x76, 0x00, 0x00, 0xF0, 0x66, 0xFD, + 0x83, 0x4D, 0x01, 0x46, + 0x28, 0x68, 0x90, 0xF8, 0xE7, 0x00, 0xC0, 0xF3, 0x41, 0x12, 0x20, 0x46, + 0xEA, 0xF7, 0xAC, 0xFD, + 0x00, 0xF0, 0x5E, 0xFD, 0x02, 0x46, 0x0B, 0x46, 0x20, 0x46, 0xEA, 0xF7, + 0xD1, 0xFD, 0xA0, 0x79, + 0x20, 0xF0, 0x02, 0x00, 0xA0, 0x71, 0x94, 0xF8, 0x6F, 0x00, 0x20, 0xF0, + 0x07, 0x00, 0x84, 0xF8, + 0x6F, 0x00, 0x94, 0xF8, 0x6E, 0x00, 0x20, 0xF0, 0x0F, 0x00, 0x84, 0xF8, + 0x6E, 0x00, 0x28, 0x68, + 0x90, 0xF8, 0xE7, 0x00, 0xC0, 0xF3, 0x41, 0x11, 0x20, 0x46, 0xEA, 0xF7, + 0xD3, 0xFD, 0x28, 0x68, + 0x90, 0xF8, 0xE7, 0x00, 0x10, 0xF0, 0x60, 0x0F, 0x94, 0xF8, 0x5E, 0x00, + 0x7E, 0xD0, 0x40, 0xF0, + 0x01, 0x00, 0x00, 0xBF, 0x84, 0xF8, 0x5E, 0x00, 0x20, 0x46, 0x00, 0xF0, + 0x6B, 0xFE, 0x04, 0x21, + 0x20, 0x46, 0xEA, 0xF7, 0x04, 0xFC, 0x28, 0x68, 0x90, 0xF8, 0xF1, 0x00, + 0xA0, 0x70, 0x28, 0x68, + 0x21, 0x8E, 0xB0, 0xF8, 0xF6, 0x20, 0x62, 0xF3, 0x08, 0x01, 0x21, 0x86, + 0x90, 0xF8, 0xF2, 0x00, + 0x00, 0xF0, 0x0F, 0x01, 0x20, 0x46, 0xEA, 0xF7, 0x52, 0xFC, 0x28, 0x68, + 0x62, 0x7D, 0x90, 0xF8, + 0xEA, 0x10, 0x61, 0xF3, 0x03, 0x02, 0x62, 0x75, 0xB0, 0xF8, 0xED, 0x20, + 0x21, 0x8A, 0x62, 0xF3, + 0x0B, 0x01, 0x21, 0x82, 0x90, 0xF8, 0xF3, 0x10, 0xA2, 0x7D, 0x61, 0xF3, + 0x03, 0x02, 0xA2, 0x75, + 0x10, 0xF8, 0xF2, 0x1F, 0x0A, 0x09, 0xA1, 0x7C, 0x62, 0xF3, 0x01, 0x01, + 0xA1, 0x74, 0x10, 0xF8, + 0x0C, 0x29, 0x92, 0x09, 0x62, 0xF3, 0x87, 0x11, 0xA1, 0x74, 0x01, 0x78, + 0xE2, 0x79, 0x61, 0xF3, + 0x00, 0x02, 0xE2, 0x71, 0xC1, 0x78, 0x61, 0x72, 0x80, 0x79, 0x01, 0x09, + 0xE0, 0x7A, 0x61, 0xF3, + 0x03, 0x00, 0xE0, 0x72, 0x4B, 0x48, 0xEA, 0xF7, 0x94, 0xFB, 0xA4, 0xF8, + 0x7C, 0x00, 0x29, 0x68, + 0x11, 0xF8, 0xE8, 0x0F, 0xC2, 0x08, 0x94, 0xF8, 0x27, 0x00, 0x62, 0xF3, + 0x83, 0x00, 0x84, 0xF8, + 0x27, 0x00, 0x11, 0xF8, 0x01, 0x29, 0x52, 0x08, 0x62, 0xF3, 0x00, 0x00, + 0x84, 0xF8, 0x27, 0x00, + 0x4A, 0x78, 0x92, 0x08, 0x62, 0xF3, 0x41, 0x00, 0x84, 0xF8, 0x27, 0x00, + 0x08, 0x78, 0xC0, 0xF3, + 0x81, 0x01, 0x20, 0x46, 0xEA, 0xF7, 0xF0, 0xFB, 0x28, 0x68, 0x90, 0xF8, + 0xE7, 0x00, 0x01, 0x09, + 0x14, 0xF8, 0x28, 0x0F, 0x61, 0xF3, 0x04, 0x10, 0x20, 0x70, 0x37, 0x48, + 0xEA, 0xF7, 0x69, 0xFB, + 0xA4, 0xF8, 0x5E, 0x00, 0x28, 0x68, 0x10, 0xF8, 0xE6, 0x1F, 0x00, 0xE0, + 0xA6, 0xE0, 0xCA, 0x08, + 0xE1, 0x7A, 0x62, 0xF3, 0x45, 0x11, 0xE1, 0x72, 0x40, 0x78, 0x41, 0x08, + 0x20, 0x78, 0x61, 0xF3, + 0x45, 0x10, 0x04, 0xF8, 0x28, 0x09, 0x20, 0x46, 0x00, 0xF0, 0x2A, 0xFD, + 0x28, 0x68, 0x90, 0xF8, + 0xEC, 0x00, 0xC0, 0xF3, 0x81, 0x01, 0x20, 0x46, 0xEA, 0xF7, 0xB3, 0xFB, + 0x14, 0xF8, 0x32, 0x0F, + 0x20, 0xF0, 0x0F, 0x00, 0x0A, 0x30, 0x20, 0xF0, 0xF0, 0x00, 0xA0, 0x30, + 0x04, 0xF8, 0x0A, 0x09, + 0x29, 0x68, 0x11, 0xF8, 0xE6, 0x0F, 0x82, 0x09, 0xE0, 0x7A, 0x62, 0xF3, + 0x00, 0x00, 0xE0, 0x72, + 0x0A, 0x78, 0x52, 0x09, 0x62, 0xF3, 0x41, 0x00, 0xE0, 0x72, 0x4A, 0x79, + 0xD2, 0x09, 0x62, 0xF3, + 0x82, 0x00, 0xE0, 0x72, 0x88, 0x7B, 0x62, 0x79, 0x60, 0xF3, 0x04, 0x02, + 0x62, 0x71, 0xC9, 0x7B, + 0x20, 0x79, 0x61, 0xF3, 0x04, 0x00, 0x20, 0x71, 0x14, 0x48, 0x94, 0xF8, + 0x37, 0x10, 0x40, 0x78, + 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, 0x37, 0x10, 0x11, 0x48, 0xEA, 0xF7, + 0x1A, 0xFB, 0xA4, 0xF8, + 0x52, 0x00, 0x28, 0x68, 0xE1, 0x88, 0xB0, 0xF8, 0xEF, 0x20, 0x62, 0xF3, + 0x0B, 0x01, 0xE1, 0x80, + 0x90, 0xF8, 0xEB, 0x10, 0xCA, 0x08, 0x21, 0x7C, 0x14, 0xE0, 0x00, 0x00, + 0x4C, 0x07, 0x10, 0x00, + 0xE6, 0x07, 0x10, 0x00, 0xB4, 0x84, 0x10, 0x00, 0x14, 0xA6, 0x01, 0x20, + 0x00, 0x84, 0x10, 0x00, + 0x95, 0x5F, 0x01, 0x00, 0x78, 0x8B, 0x01, 0x20, 0x20, 0xBF, 0x01, 0x20, + 0x16, 0xBF, 0x01, 0x20, + 0x00, 0x9B, 0x01, 0x20, 0x62, 0xF3, 0x02, 0x01, 0x21, 0x74, 0x10, 0xF8, + 0xDF, 0x1F, 0xA2, 0x78, + 0x61, 0xF3, 0x03, 0x02, 0xA2, 0x70, 0x01, 0x78, 0x0A, 0x09, 0xE1, 0x78, + 0x62, 0xF3, 0x03, 0x01, + 0xE1, 0x70, 0xC1, 0x7A, 0x0A, 0x09, 0x61, 0x78, 0x62, 0xF3, 0x02, 0x01, + 0x61, 0x70, 0x41, 0x7A, + 0x8A, 0x09, 0x21, 0x78, 0x62, 0xF3, 0x00, 0x01, 0x21, 0x70, 0xC1, 0x79, + 0xCA, 0x09, 0x21, 0x7B, + 0x62, 0xF3, 0x00, 0x01, 0x21, 0x73, 0x94, 0xF8, 0x37, 0x10, 0x41, 0xF0, + 0x20, 0x01, 0x84, 0xF8, + 0x37, 0x10, 0x21, 0x8F, 0x6F, 0xF3, 0x08, 0x01, 0x01, 0xF5, 0x80, 0x71, + 0x21, 0x87, 0x00, 0x21, + 0xC4, 0xF8, 0x3A, 0x10, 0x01, 0x7B, 0x8A, 0x09, 0xE1, 0x7A, 0x62, 0xF3, + 0xC3, 0x01, 0xE1, 0x72, + 0xC0, 0x79, 0x00, 0x09, 0x60, 0xF3, 0x04, 0x11, 0xE1, 0x72, 0x70, 0xBD, + 0x20, 0xF0, 0x01, 0x00, + 0xD8, 0xE6, 0x70, 0xB5, 0x04, 0x46, 0xEA, 0xF7, 0xAF, 0xFA, 0xFD, 0x48, + 0xEA, 0xF7, 0xB1, 0xFA, + 0xA4, 0xF8, 0x76, 0x00, 0x00, 0xF0, 0x00, 0xFC, 0xFA, 0x4D, 0x01, 0x46, + 0x28, 0x68, 0x90, 0xF8, + 0xC9, 0x00, 0xC0, 0xF3, 0x41, 0x12, 0x20, 0x46, 0xEA, 0xF7, 0x46, 0xFC, + 0x00, 0xF0, 0xF8, 0xFB, + 0x02, 0x46, 0x0B, 0x46, 0x20, 0x46, 0xEA, 0xF7, 0x6B, 0xFC, 0xA0, 0x79, + 0x20, 0xF0, 0x02, 0x00, + 0xA0, 0x71, 0x94, 0xF8, 0x6F, 0x00, 0x20, 0xF0, 0x07, 0x00, 0x84, 0xF8, + 0x6F, 0x00, 0x94, 0xF8, + 0x6E, 0x00, 0x20, 0xF0, 0x0F, 0x00, 0x84, 0xF8, 0x6E, 0x00, 0x28, 0x68, + 0x90, 0xF8, 0xC9, 0x00, + 0xC0, 0xF3, 0x41, 0x11, 0x20, 0x46, 0xEA, 0xF7, 0x6D, 0xFC, 0x28, 0x68, + 0x90, 0xF8, 0xC9, 0x00, + 0x10, 0xF0, 0x60, 0x0F, 0x94, 0xF8, 0x5E, 0x00, 0x7E, 0xD0, 0x40, 0xF0, + 0x01, 0x00, 0x00, 0xBF, + 0x84, 0xF8, 0x5E, 0x00, 0x20, 0x46, 0x00, 0xF0, 0x05, 0xFD, 0x28, 0x68, + 0x90, 0xF8, 0xD3, 0x00, + 0xA0, 0x70, 0x28, 0x68, 0x21, 0x8E, 0xB0, 0xF8, 0xD8, 0x20, 0x62, 0xF3, + 0x08, 0x01, 0x21, 0x86, + 0x90, 0xF8, 0xD4, 0x00, 0x00, 0xF0, 0x0F, 0x01, 0x20, 0x46, 0xEA, 0xF7, + 0xF0, 0xFA, 0x28, 0x68, + 0x62, 0x7D, 0x90, 0xF8, 0xCC, 0x10, 0x61, 0xF3, 0x03, 0x02, 0x62, 0x75, + 0xB0, 0xF8, 0xCF, 0x20, + 0x21, 0x8A, 0x62, 0xF3, 0x0B, 0x01, 0x21, 0x82, 0x90, 0xF8, 0xD5, 0x10, + 0xA2, 0x7D, 0x61, 0xF3, + 0x03, 0x02, 0xA2, 0x75, 0x90, 0xF8, 0xF2, 0x21, 0xA1, 0x89, 0x62, 0xF3, + 0x0B, 0x01, 0xA1, 0x81, + 0x10, 0xF8, 0xD4, 0x1F, 0x0A, 0x09, 0xA1, 0x7C, 0x62, 0xF3, 0x01, 0x01, + 0xA1, 0x74, 0x10, 0xF8, + 0x0C, 0x29, 0x92, 0x09, 0x62, 0xF3, 0x87, 0x11, 0xA1, 0x74, 0x01, 0x78, + 0xE2, 0x79, 0x61, 0xF3, + 0x00, 0x02, 0xE2, 0x71, 0xC1, 0x78, 0x61, 0x72, 0x80, 0x79, 0x01, 0x09, + 0xE0, 0x7A, 0x61, 0xF3, + 0x03, 0x00, 0xE0, 0x72, 0xBC, 0x48, 0xEA, 0xF7, 0x2C, 0xFA, 0xA4, 0xF8, + 0x7C, 0x00, 0x29, 0x68, + 0x11, 0xF8, 0xCA, 0x0F, 0xC2, 0x08, 0x94, 0xF8, 0x27, 0x00, 0x62, 0xF3, + 0x83, 0x00, 0x84, 0xF8, + 0x27, 0x00, 0x11, 0xF8, 0x01, 0x29, 0x52, 0x08, 0x62, 0xF3, 0x00, 0x00, + 0x84, 0xF8, 0x27, 0x00, + 0x4A, 0x78, 0x92, 0x08, 0x62, 0xF3, 0x41, 0x00, 0x84, 0xF8, 0x27, 0x00, + 0x08, 0x78, 0xC0, 0xF3, + 0x81, 0x01, 0x20, 0x46, 0xEA, 0xF7, 0x88, 0xFA, 0x28, 0x68, 0x90, 0xF8, + 0xC9, 0x00, 0x01, 0x09, + 0x14, 0xF8, 0x28, 0x0F, 0x61, 0xF3, 0x04, 0x10, 0x20, 0x70, 0xA8, 0x48, + 0xEA, 0xF7, 0x01, 0xFA, + 0xA4, 0xF8, 0x5E, 0x00, 0x28, 0x68, 0x00, 0xE0, 0xA1, 0xE0, 0x10, 0xF8, + 0xC8, 0x1F, 0xCA, 0x08, + 0xE1, 0x7A, 0x62, 0xF3, 0x45, 0x11, 0xE1, 0x72, 0x40, 0x78, 0x41, 0x08, + 0x20, 0x78, 0x61, 0xF3, + 0x45, 0x10, 0x04, 0xF8, 0x28, 0x09, 0x20, 0x46, 0x00, 0xF0, 0xC2, 0xFB, + 0x28, 0x68, 0x90, 0xF8, + 0xCE, 0x00, 0xC0, 0xF3, 0x81, 0x01, 0x20, 0x46, 0xEA, 0xF7, 0x4B, 0xFA, + 0x14, 0xF8, 0x32, 0x0F, + 0x20, 0xF0, 0x0F, 0x00, 0x0A, 0x30, 0x20, 0xF0, 0xF0, 0x00, 0xA0, 0x30, + 0x04, 0xF8, 0x0A, 0x09, + 0x29, 0x68, 0x11, 0xF8, 0xC8, 0x0F, 0x82, 0x09, 0xE0, 0x7A, 0x62, 0xF3, + 0x00, 0x00, 0xE0, 0x72, + 0x0A, 0x78, 0x52, 0x09, 0x62, 0xF3, 0x41, 0x00, 0xE0, 0x72, 0x4A, 0x79, + 0xD2, 0x09, 0x62, 0xF3, + 0x82, 0x00, 0xE0, 0x72, 0x88, 0x7B, 0x62, 0x79, 0x60, 0xF3, 0x04, 0x02, + 0x62, 0x71, 0xC8, 0x7B, + 0x21, 0x79, 0x60, 0xF3, 0x04, 0x01, 0x86, 0x48, 0x21, 0x71, 0x94, 0xF8, + 0x37, 0x10, 0x40, 0x78, + 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, 0x37, 0x10, 0x82, 0x48, 0xEA, 0xF7, + 0xB2, 0xF9, 0xA4, 0xF8, + 0x52, 0x00, 0x28, 0x68, 0xE1, 0x88, 0xB0, 0xF8, 0xD1, 0x20, 0x62, 0xF3, + 0x0B, 0x01, 0xE1, 0x80, + 0x10, 0xF8, 0xCD, 0x1F, 0xCA, 0x08, 0x21, 0x7C, 0x62, 0xF3, 0x02, 0x01, + 0x21, 0x74, 0x10, 0xF8, + 0x12, 0x1F, 0xA2, 0x78, 0x61, 0xF3, 0x03, 0x02, 0xA2, 0x70, 0x10, 0xF8, + 0x17, 0x19, 0x0A, 0x09, + 0xE1, 0x78, 0x62, 0xF3, 0x03, 0x01, 0xE1, 0x70, 0x01, 0x79, 0x0A, 0x09, + 0x61, 0x78, 0x62, 0xF3, + 0x02, 0x01, 0x61, 0x70, 0x81, 0x78, 0x8A, 0x09, 0x21, 0x78, 0x62, 0xF3, + 0x00, 0x01, 0x21, 0x70, + 0x01, 0x78, 0xCA, 0x09, 0x21, 0x7B, 0x62, 0xF3, 0x00, 0x01, 0x21, 0x73, + 0x01, 0x79, 0xCA, 0x09, + 0x94, 0xF8, 0x37, 0x10, 0x62, 0xF3, 0x45, 0x11, 0x84, 0xF8, 0x37, 0x10, + 0x22, 0x8F, 0x01, 0xF0, + 0x1F, 0x01, 0x6F, 0xF3, 0x08, 0x02, 0x02, 0xF5, 0x80, 0x72, 0x22, 0x87, + 0x83, 0x7B, 0xC2, 0x7A, + 0x03, 0xF0, 0x1F, 0x03, 0x5B, 0x1C, 0xC3, 0xEB, 0x43, 0x23, 0x5B, 0x00, + 0x5A, 0x43, 0xCA, 0x40, + 0x51, 0x08, 0xC4, 0xF8, 0x3A, 0x10, 0x41, 0x79, 0x8A, 0x09, 0xE1, 0x7A, + 0x62, 0xF3, 0xC3, 0x01, + 0xE1, 0x72, 0x00, 0x78, 0x00, 0x09, 0x60, 0xF3, 0x04, 0x11, 0xE1, 0x72, + 0x70, 0xBD, 0x20, 0xF0, + 0x01, 0x00, 0xDD, 0xE6, 0x10, 0xB5, 0x04, 0x46, 0xA4, 0x22, 0x53, 0x49, + 0x00, 0xF0, 0xA5, 0xFD, + 0x52, 0x48, 0xC1, 0x78, 0xA0, 0x89, 0x61, 0xF3, 0x0B, 0x00, 0xA0, 0x81, + 0x10, 0xBD, 0x70, 0xB5, + 0x04, 0x46, 0xFF, 0xF7, 0xEF, 0xFF, 0x00, 0xF0, 0x97, 0xFA, 0x01, 0x46, + 0x00, 0x22, 0x20, 0x46, + 0xEA, 0xF7, 0xE2, 0xFA, 0x4A, 0x48, 0xEA, 0xF7, 0x3C, 0xF9, 0x42, 0x4D, + 0xA4, 0xF8, 0x7C, 0x00, + 0x28, 0x68, 0x90, 0xF8, 0xF8, 0x00, 0xA0, 0x70, 0x28, 0x68, 0x90, 0xF8, + 0xF9, 0x00, 0x00, 0xF0, + 0x0F, 0x01, 0x20, 0x46, 0xEA, 0xF7, 0xBB, 0xF9, 0x28, 0x68, 0x10, 0xF8, + 0xF9, 0x1F, 0x0A, 0x09, + 0xA1, 0x7C, 0x62, 0xF3, 0x01, 0x01, 0xA1, 0x74, 0x02, 0x78, 0x92, 0x09, + 0x62, 0xF3, 0x87, 0x11, + 0xA1, 0x74, 0x81, 0x78, 0x94, 0xF8, 0x2D, 0x20, 0x61, 0xF3, 0x04, 0x02, + 0x84, 0xF8, 0x2D, 0x20, + 0xC1, 0x78, 0x94, 0xF8, 0x2C, 0x20, 0x61, 0xF3, 0x04, 0x02, 0x84, 0xF8, + 0x2C, 0x20, 0x40, 0x78, + 0xA1, 0x7D, 0x60, 0xF3, 0x03, 0x01, 0xA1, 0x75, 0x00, 0x21, 0x20, 0x46, + 0xEA, 0xF7, 0xF2, 0xFA, + 0x14, 0xF8, 0x5E, 0x0F, 0x20, 0xF0, 0x01, 0x00, 0x04, 0xF8, 0x01, 0x0B, + 0x28, 0x48, 0x21, 0x78, + 0x00, 0x79, 0x60, 0xF3, 0x04, 0x01, 0x04, 0xF8, 0x2F, 0x19, 0x28, 0x68, + 0xB0, 0xF8, 0xFD, 0x10, + 0x20, 0x88, 0x61, 0xF3, 0x08, 0x00, 0x20, 0x80, 0x70, 0xBD, 0x70, 0xB5, + 0x1D, 0x4E, 0x03, 0x28, + 0x34, 0x68, 0x04, 0xF2, 0x5E, 0x62, 0x04, 0xF6, 0x6E, 0x05, 0x15, 0xD0, + 0x04, 0x28, 0x21, 0xD0, + 0x94, 0xF8, 0x51, 0x06, 0x94, 0xF8, 0x50, 0x16, 0x02, 0xEB, 0x40, 0x00, + 0x00, 0xF0, 0x77, 0xFA, + 0x30, 0x68, 0x90, 0xF8, 0x60, 0x18, 0x90, 0xF8, 0x61, 0x08, 0x00, 0xBF, + 0x05, 0xEB, 0x40, 0x00, + 0xBD, 0xE8, 0x70, 0x40, 0x00, 0xF0, 0x82, 0xBA, 0x94, 0xF8, 0x53, 0x06, + 0x94, 0xF8, 0x52, 0x16, + 0x02, 0xEB, 0x40, 0x00, 0x00, 0xF0, 0x63, 0xFA, 0x30, 0x68, 0x90, 0xF8, + 0x62, 0x18, 0x90, 0xF8, + 0x63, 0x08, 0xEB, 0xE7, 0x94, 0xF8, 0x55, 0x06, 0x94, 0xF8, 0x54, 0x16, + 0x02, 0xEB, 0x40, 0x00, + 0x00, 0xF0, 0x55, 0xFA, 0x30, 0x68, 0x90, 0xF8, 0x64, 0x18, 0x90, 0xF8, + 0x65, 0x08, 0xDD, 0xE7, + 0x14, 0xA6, 0x01, 0x20, 0x4C, 0x07, 0x10, 0x00, 0x78, 0x8B, 0x01, 0x20, + 0x20, 0xBF, 0x01, 0x20, + 0x16, 0xBF, 0x01, 0x20, 0x00, 0x9B, 0x01, 0x20, 0x5C, 0x83, 0x10, 0x00, + 0x74, 0x07, 0x10, 0x00, + 0x08, 0x92, 0x01, 0x20, 0x2D, 0xE9, 0xF0, 0x47, 0x85, 0x4D, 0x4F, 0xF0, + 0x01, 0x09, 0x00, 0x26, + 0x85, 0xF8, 0x00, 0x90, 0xAE, 0x70, 0x83, 0x4F, 0xDF, 0xF8, 0x0C, 0x82, + 0x04, 0x46, 0xEE, 0x70, + 0x09, 0x29, 0x66, 0xD2, 0xDF, 0xE8, 0x01, 0xF0, 0x65, 0x05, 0x09, 0x18, + 0x44, 0x2F, 0x48, 0x5E, + 0x62, 0x00, 0x20, 0x46, 0xFF, 0xF7, 0x36, 0xFF, 0x5B, 0xE0, 0x20, 0x46, + 0xFF, 0xF7, 0x32, 0xFF, + 0xB8, 0x78, 0x94, 0xF8, 0x5F, 0x10, 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, + 0x5F, 0x10, 0xD8, 0xF8, + 0x00, 0x00, 0x90, 0xF8, 0xFF, 0x00, 0x12, 0xE0, 0x20, 0x46, 0xFF, 0xF7, + 0x23, 0xFF, 0xD8, 0xF8, + 0x00, 0x10, 0x91, 0xF8, 0x01, 0x11, 0xA1, 0x70, 0xF9, 0x78, 0x94, 0xF8, + 0x5F, 0x20, 0x61, 0xF3, + 0x04, 0x02, 0x84, 0xF8, 0x5F, 0x20, 0xD8, 0xF8, 0x00, 0x00, 0x90, 0xF8, + 0x00, 0x01, 0x00, 0xF0, + 0x03, 0x00, 0xA8, 0x70, 0x35, 0xE0, 0x20, 0x46, 0xFF, 0xF7, 0x0C, 0xFF, + 0x00, 0x21, 0x20, 0x46, + 0xEA, 0xF7, 0xED, 0xF8, 0x94, 0xF8, 0x5E, 0x00, 0x20, 0xF0, 0x01, 0x00, + 0x84, 0xF8, 0x5E, 0x00, + 0x78, 0x79, 0x94, 0xF8, 0x5F, 0x10, 0x60, 0xF3, 0x04, 0x01, 0x84, 0xF8, + 0x5F, 0x10, 0x17, 0xE0, + 0x20, 0x46, 0xFF, 0xF7, 0x04, 0xFF, 0x1C, 0xE0, 0x20, 0x46, 0xFF, 0xF7, + 0x00, 0xFF, 0x00, 0x21, + 0x20, 0x46, 0xEA, 0xF7, 0xD4, 0xF8, 0xB8, 0x79, 0x94, 0xF8, 0x5F, 0x10, + 0x60, 0xF3, 0x04, 0x01, + 0x84, 0xF8, 0x5F, 0x10, 0x94, 0xF8, 0x5E, 0x00, 0x20, 0xF0, 0x01, 0x00, + 0x84, 0xF8, 0x5E, 0x00, + 0x2E, 0x70, 0x06, 0xE0, 0x20, 0x46, 0xFF, 0xF7, 0x7C, 0xFD, 0xF9, 0xE7, + 0x20, 0x46, 0x00, 0xF0, + 0x59, 0xF8, 0x20, 0x46, 0x00, 0xF0, 0xAA, 0xFA, 0x94, 0xF8, 0x27, 0x00, + 0xC0, 0x07, 0x01, 0xD0, + 0x6E, 0x70, 0x01, 0xE0, 0x85, 0xF8, 0x01, 0x90, 0xA0, 0x89, 0xC0, 0xF3, + 0x0B, 0x00, 0xE8, 0x80, + 0xBD, 0xE8, 0xF0, 0x87, 0x7F, 0xB5, 0x00, 0xF0, 0x6F, 0xF9, 0x01, 0x90, + 0x00, 0xF0, 0x70, 0xF9, + 0xCD, 0xE9, 0x02, 0x01, 0x04, 0x21, 0x01, 0xA8, 0xEA, 0xF7, 0xBD, 0xFC, + 0x3C, 0x4C, 0x08, 0x21, + 0x20, 0x71, 0x02, 0xA8, 0xEA, 0xF7, 0xB7, 0xFC, 0x60, 0x71, 0x3A, 0x48, + 0x00, 0x21, 0x80, 0x1E, + 0x38, 0x4D, 0x40, 0xF8, 0x02, 0x1F, 0x01, 0x24, 0x41, 0x60, 0x01, 0x72, + 0xE0, 0xB2, 0xFF, 0xF7, + 0xF5, 0xFA, 0x28, 0x55, 0x64, 0x1C, 0x09, 0x2C, 0xF8, 0xDB, 0x34, 0x48, + 0xFF, 0xF7, 0xDB, 0xFB, + 0x7F, 0xBD, 0x70, 0xB5, 0x31, 0x4D, 0x04, 0x79, 0xA4, 0x35, 0x8C, 0xB1, + 0x21, 0x46, 0x28, 0x46, + 0xFF, 0xF7, 0x48, 0xFF, 0xA8, 0x7C, 0x00, 0xF0, 0x03, 0x00, 0x00, 0xF0, + 0xAF, 0xF9, 0x20, 0x46, + 0xFF, 0xF7, 0xF3, 0xFE, 0x2A, 0x49, 0x28, 0x46, 0xEA, 0xF7, 0xD8, 0xF9, + 0x00, 0x20, 0x70, 0xBD, + 0x01, 0x20, 0x70, 0xBD, 0x40, 0xF2, 0xFF, 0x10, 0xC1, 0xEB, 0x41, 0x21, + 0x91, 0xFB, 0xF0, 0xF0, + 0x00, 0x20, 0x70, 0x47, 0x10, 0xB5, 0x04, 0x46, 0xFF, 0xF7, 0x7C, 0xFE, + 0x94, 0xF8, 0x37, 0x00, + 0x40, 0xF0, 0x10, 0x00, 0x84, 0xF8, 0x37, 0x00, 0xA1, 0x89, 0x94, 0xF8, + 0x33, 0x00, 0x6F, 0xF3, + 0x0B, 0x01, 0x10, 0x31, 0xA1, 0x81, 0x21, 0x8A, 0x20, 0xF0, 0x23, 0x00, + 0x6F, 0xF3, 0x0B, 0x01, + 0x40, 0x31, 0x21, 0x82, 0x08, 0x21, 0xA1, 0x70, 0x94, 0xF8, 0x5F, 0x10, + 0x40, 0xF0, 0x0C, 0x00, + 0x21, 0xF0, 0x1F, 0x01, 0x84, 0xF8, 0x5F, 0x10, 0x21, 0x8E, 0x6F, 0xF3, + 0x08, 0x01, 0x21, 0x86, + 0x84, 0xF8, 0x33, 0x00, 0x0C, 0x48, 0x01, 0x21, 0x00, 0x68, 0x90, 0xF8, + 0xE7, 0x00, 0xC0, 0xF3, + 0x41, 0x12, 0x20, 0x46, 0xEA, 0xF7, 0x48, 0xF9, 0x94, 0xF8, 0x28, 0x00, + 0x40, 0xF0, 0x20, 0x00, + 0x84, 0xF8, 0x28, 0x00, 0x20, 0x46, 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, + 0x71, 0xB9, 0x00, 0x00, + 0xE6, 0x07, 0x10, 0x00, 0x16, 0xBF, 0x01, 0x20, 0x4C, 0x07, 0x10, 0x00, + 0x5C, 0x83, 0x10, 0x00, + 0x95, 0x5F, 0x01, 0x00, 0x70, 0xB5, 0x00, 0xF0, 0x72, 0xFA, 0xFF, 0xF7, + 0x6B, 0xFF, 0xFF, 0xF7, + 0x17, 0xFA, 0xFF, 0xF7, 0xD5, 0xF8, 0xFE, 0xF7, 0xD9, 0xFE, 0xFE, 0xF7, + 0xF7, 0xF9, 0xFD, 0xF7, + 0x67, 0xFF, 0xFE, 0xF7, 0xA8, 0xFA, 0x50, 0x48, 0x00, 0x25, 0x70, 0x21, + 0x45, 0x60, 0x4F, 0x48, + 0x00, 0xF0, 0x6C, 0xFC, 0x4E, 0x48, 0x04, 0x68, 0x94, 0xF8, 0xE7, 0x00, + 0xC0, 0x06, 0x05, 0xD5, + 0x28, 0x22, 0x04, 0xF5, 0x0F, 0x61, 0x49, 0x48, 0x00, 0xF0, 0xBF, 0xFB, + 0x94, 0xF8, 0x33, 0x01, + 0xC0, 0x06, 0x0D, 0xD5, 0x45, 0x48, 0x20, 0x22, 0x04, 0xF6, 0x16, 0x11, + 0x28, 0x30, 0x00, 0xF0, + 0xB4, 0xFB, 0x42, 0x48, 0x28, 0x22, 0x04, 0xF6, 0x3F, 0x11, 0x48, 0x30, + 0x00, 0xF0, 0xAD, 0xFB, + 0x40, 0x48, 0x05, 0x70, 0x70, 0xBD, 0x38, 0xB1, 0x01, 0x28, 0x07, 0xD0, + 0x02, 0x28, 0x07, 0xD0, + 0x17, 0x20, 0x00, 0x21, 0xFB, 0xF7, 0x65, 0xBD, 0x14, 0x20, 0xFA, 0xE7, + 0x15, 0x20, 0xF8, 0xE7, + 0x16, 0x20, 0xF6, 0xE7, 0x00, 0x21, 0x01, 0x60, 0x41, 0x60, 0x81, 0x60, + 0xC1, 0x60, 0x70, 0x47, + 0x70, 0xB5, 0x31, 0x4C, 0x34, 0x4D, 0x20, 0x68, 0x09, 0xE0, 0x00, 0xBF, + 0x55, 0xF8, 0x20, 0x10, + 0x32, 0x48, 0x88, 0x47, 0x00, 0x28, 0x11, 0xD0, 0x20, 0x68, 0x40, 0x1C, + 0x20, 0x60, 0x09, 0x28, + 0xF4, 0xD3, 0x60, 0x68, 0x2D, 0x49, 0x40, 0x1C, 0x10, 0x31, 0x00, 0x22, + 0x60, 0x60, 0x0A, 0x70, + 0x48, 0x60, 0x2A, 0x48, 0x01, 0x68, 0x10, 0x30, 0x88, 0x47, 0x01, 0x20, + 0x70, 0xBD, 0x70, 0xB5, + 0x04, 0x46, 0x00, 0x79, 0x00, 0x25, 0x60, 0xB9, 0xE0, 0x79, 0x50, 0xB9, + 0xA0, 0x79, 0x40, 0xB9, + 0x20, 0x7A, 0x30, 0xB9, 0x60, 0x79, 0x20, 0xB9, 0x60, 0x7A, 0x10, 0xB9, + 0xA0, 0x7A, 0x00, 0x28, + 0x12, 0xD0, 0x1E, 0x48, 0x34, 0x21, 0x10, 0x30, 0x00, 0xF0, 0x00, 0xFC, + 0x94, 0xE8, 0x4E, 0x00, + 0x1A, 0x48, 0x80, 0xE8, 0x4E, 0x00, 0x14, 0x48, 0x16, 0x49, 0x05, 0x60, + 0x60, 0x7B, 0x08, 0x70, + 0x16, 0x48, 0xFF, 0xF7, 0xBD, 0xFF, 0x01, 0x20, 0x70, 0xBD, 0x0F, 0x49, + 0x50, 0xB1, 0x4A, 0x68, + 0x52, 0x1C, 0x4A, 0x60, 0x11, 0x49, 0x10, 0x31, 0x08, 0x70, 0x10, 0x48, + 0x4A, 0x60, 0x01, 0x68, + 0x10, 0x30, 0x08, 0x47, 0x08, 0x68, 0x40, 0x1C, 0x08, 0x60, 0x0C, 0x48, + 0xA8, 0xE7, 0x00, 0xF0, + 0x3B, 0xB8, 0x00, 0xF0, 0x3D, 0xB8, 0x00, 0xF0, 0x40, 0xB8, 0x00, 0xF0, + 0x43, 0xB8, 0x00, 0xF0, + 0x48, 0xB8, 0x00, 0xF0, 0x4B, 0xB8, 0x00, 0x00, 0xF0, 0x07, 0x10, 0x00, + 0x20, 0xBF, 0x01, 0x20, + 0x4C, 0x07, 0x10, 0x00, 0xF9, 0x07, 0x10, 0x00, 0x0C, 0x7D, 0x01, 0x00, + 0xA4, 0x84, 0x10, 0x00, + 0x70, 0xB5, 0x00, 0x23, 0x14, 0x46, 0x08, 0xE0, 0x31, 0xF8, 0x13, 0x50, + 0x31, 0xF8, 0x14, 0x60, + 0x35, 0x44, 0x20, 0xF8, 0x13, 0x50, 0x5B, 0x1C, 0x64, 0x1C, 0x93, 0x42, + 0xF4, 0xDB, 0x70, 0xBD, + 0x30, 0xB4, 0x00, 0x24, 0x43, 0xB9, 0x0B, 0xE0, 0x30, 0xF8, 0x14, 0x30, + 0x31, 0xF8, 0x14, 0x50, + 0x2B, 0x44, 0x20, 0xF8, 0x14, 0x30, 0x64, 0x1C, 0x94, 0x42, 0xF5, 0xDB, + 0x30, 0xBC, 0x70, 0x47, + 0x30, 0xBC, 0x52, 0x00, 0x00, 0xF0, 0x01, 0xBB, 0xBF, 0x48, 0x00, 0x68, + 0x80, 0x6A, 0x70, 0x47, + 0xBD, 0x48, 0x00, 0x68, 0x41, 0x6A, 0x00, 0x6A, 0x70, 0x47, 0xBB, 0x48, + 0x00, 0x68, 0xD0, 0xF8, + 0x6A, 0x04, 0x70, 0x47, 0xB8, 0x48, 0x00, 0x68, 0xD0, 0xF8, 0x66, 0x14, + 0xD0, 0xF8, 0x62, 0x04, + 0x70, 0x47, 0xB5, 0x48, 0x00, 0x68, 0xD0, 0xF8, 0x38, 0x0A, 0x70, 0x47, + 0xB2, 0x48, 0x00, 0x68, + 0x00, 0xF5, 0x23, 0x60, 0x03, 0xC8, 0x70, 0x47, 0xF0, 0xB5, 0x00, 0x24, + 0x25, 0x46, 0xAF, 0x4E, + 0x4F, 0xF4, 0x00, 0x67, 0x14, 0xE0, 0x00, 0xBF, 0x30, 0xF8, 0x15, 0x30, + 0xC3, 0xF3, 0x0B, 0x03, + 0x5F, 0xEA, 0xD3, 0x2C, 0x00, 0xD0, 0x33, 0x43, 0x00, 0x2B, 0x00, 0xDA, + 0x5B, 0x42, 0x9C, 0x42, + 0x00, 0xDA, 0x9C, 0xB2, 0xBC, 0x42, 0x02, 0xD3, 0x40, 0xF2, 0xFF, 0x74, + 0x02, 0xE0, 0x6D, 0x1C, + 0x8D, 0x42, 0xE9, 0xDB, 0xD4, 0x40, 0x01, 0x20, 0xA0, 0x40, 0x80, 0xB2, + 0xF0, 0xBD, 0x30, 0xB5, + 0xA0, 0x4B, 0x9F, 0x4C, 0x5A, 0x68, 0x82, 0x42, 0x02, 0xD1, 0xDA, 0x68, + 0x8A, 0x42, 0x0A, 0xD0, + 0x00, 0x22, 0x06, 0xE0, 0x30, 0xF8, 0x12, 0x50, 0xC5, 0xF3, 0x0B, 0x05, + 0x24, 0xF8, 0x12, 0x50, + 0x52, 0x1C, 0x8A, 0x42, 0xF6, 0xDB, 0xD9, 0x60, 0x58, 0x60, 0x30, 0xBD, + 0x30, 0xB5, 0x95, 0x4B, + 0x95, 0x4C, 0x9A, 0x68, 0x82, 0x42, 0x02, 0xD1, 0x1A, 0x69, 0x8A, 0x42, + 0x0D, 0xD0, 0x00, 0x22, + 0x07, 0xE0, 0x00, 0xBF, 0x30, 0xF8, 0x12, 0x50, 0xC5, 0xF3, 0x0B, 0x05, + 0x24, 0xF8, 0x12, 0x50, + 0x52, 0x1C, 0x8A, 0x42, 0xF6, 0xDB, 0x19, 0x61, 0x98, 0x60, 0x30, 0xBD, + 0x70, 0xB5, 0x04, 0x46, + 0x8A, 0x48, 0x01, 0x68, 0x02, 0x29, 0x0A, 0xD1, 0x86, 0x4D, 0x29, 0x78, + 0x8C, 0x42, 0x06, 0xD0, + 0x00, 0xEB, 0x84, 0x00, 0xD0, 0xF8, 0x9C, 0x00, 0xE9, 0xF7, 0x3D, 0xFE, + 0x2C, 0x70, 0x70, 0xBD, + 0x10, 0xB5, 0x04, 0x46, 0x90, 0xF8, 0x28, 0x00, 0x80, 0x06, 0x1B, 0xD5, + 0x7A, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x70, 0x01, 0x80, 0x07, 0x01, 0xD5, 0x7D, 0x48, 0x0F, 0xE0, + 0x7D, 0x49, 0x08, 0x68, + 0x00, 0x28, 0x0F, 0xD1, 0xA0, 0x7C, 0x94, 0xF8, 0x27, 0x20, 0x80, 0x09, + 0xC0, 0xEB, 0xC0, 0x00, + 0x12, 0xF0, 0x01, 0x0F, 0x01, 0xEB, 0x00, 0x10, 0x05, 0xD0, 0x00, 0x1D, + 0xE9, 0xF7, 0x09, 0xFE, + 0xA4, 0xF8, 0x8C, 0x00, 0x10, 0xBD, 0x00, 0xF5, 0xAA, 0x70, 0xF7, 0xE7, + 0x70, 0xB5, 0x04, 0x46, + 0x90, 0xF8, 0x28, 0x00, 0x80, 0x06, 0x28, 0xD5, 0x67, 0x48, 0x00, 0x68, + 0x90, 0xF8, 0x88, 0x01, + 0xC0, 0x06, 0x08, 0xD5, 0x6A, 0x48, 0x28, 0x30, 0xE9, 0xF7, 0xF3, 0xFD, + 0x24, 0xF8, 0x8E, 0x0F, + 0x67, 0x48, 0x48, 0x30, 0x16, 0xE0, 0x67, 0x48, 0x01, 0x68, 0x00, 0x29, + 0x15, 0xD1, 0xA1, 0x7C, + 0x94, 0xF8, 0x27, 0x20, 0x89, 0x09, 0xC1, 0xEB, 0xC1, 0x01, 0x12, 0xF0, + 0x01, 0x0F, 0x00, 0xEB, + 0x01, 0x15, 0x0B, 0xD0, 0x05, 0xF1, 0x2C, 0x00, 0xE9, 0xF7, 0xDB, 0xFD, + 0x24, 0xF8, 0x8E, 0x0F, + 0x05, 0xF1, 0x4C, 0x00, 0xE9, 0xF7, 0xD5, 0xFD, 0x60, 0x80, 0x70, 0xBD, + 0x05, 0xF5, 0xBE, 0x70, + 0xE9, 0xF7, 0xCF, 0xFD, 0x24, 0xF8, 0x8E, 0x0F, 0x05, 0xF5, 0xCE, 0x70, + 0xF2, 0xE7, 0x70, 0xB5, + 0x04, 0x46, 0x90, 0xF8, 0x28, 0x00, 0x80, 0x06, 0x0B, 0xD5, 0x4B, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0x88, 0x01, 0xC0, 0x06, 0x06, 0xD5, 0x4E, 0x48, 0x70, 0x30, 0xE9, 0xF7, + 0xBA, 0xFD, 0xA4, 0xF8, + 0x8E, 0x00, 0x70, 0xBD, 0x4B, 0x48, 0x01, 0x68, 0x00, 0x29, 0xFA, 0xD1, + 0xA1, 0x7C, 0x94, 0xF8, + 0x27, 0x20, 0x89, 0x09, 0xC1, 0xEB, 0xC1, 0x01, 0x12, 0xF0, 0x01, 0x0F, + 0x00, 0xEB, 0x01, 0x15, + 0x0C, 0xD0, 0x05, 0xF1, 0x2C, 0x00, 0xE9, 0xF7, 0xA4, 0xFD, 0x24, 0xF8, + 0x8E, 0x0F, 0x05, 0xF1, + 0x4C, 0x00, 0x00, 0xBF, 0xE9, 0xF7, 0x9D, 0xFD, 0x60, 0x80, 0x70, 0xBD, + 0x05, 0xF5, 0xBE, 0x70, + 0xE9, 0xF7, 0x97, 0xFD, 0x24, 0xF8, 0x8E, 0x0F, 0x05, 0xF5, 0xCE, 0x70, + 0xF2, 0xE7, 0x70, 0x47, + 0x70, 0x47, 0x70, 0x47, 0x02, 0x00, 0x4F, 0xF0, 0x00, 0x00, 0x00, 0xD1, + 0x08, 0x46, 0x70, 0x47, + 0x02, 0x46, 0x00, 0x20, 0x01, 0x2A, 0x00, 0xD1, 0x08, 0x46, 0x70, 0x47, + 0x2A, 0x49, 0x10, 0xB5, + 0x09, 0x68, 0x91, 0xF8, 0xB0, 0x10, 0xCA, 0x07, 0x08, 0xD0, 0x2A, 0x4C, + 0x62, 0x78, 0x01, 0x2A, + 0x05, 0xD0, 0x02, 0x21, 0xE9, 0xF7, 0xA3, 0xFD, 0x00, 0x20, 0x60, 0x70, + 0x10, 0xBD, 0xC1, 0xF3, + 0xC1, 0x01, 0xF7, 0xE7, 0x20, 0x49, 0x0A, 0x68, 0x92, 0xF8, 0xB0, 0x20, + 0x93, 0x09, 0x10, 0xF8, + 0x3E, 0x2B, 0x63, 0xF3, 0x82, 0x02, 0x00, 0xF8, 0x3E, 0x2C, 0x0B, 0x68, + 0x93, 0xF8, 0xB0, 0x30, + 0x5B, 0x09, 0x63, 0xF3, 0x45, 0x12, 0x00, 0xF8, 0x3E, 0x2C, 0x09, 0x68, + 0xB1, 0xF8, 0xB7, 0x20, + 0x02, 0x82, 0x91, 0xF8, 0xB6, 0x20, 0x83, 0x7F, 0x62, 0xF3, 0x07, 0x13, + 0x83, 0x77, 0x91, 0xF8, + 0xB3, 0x20, 0x13, 0x09, 0x02, 0x7D, 0x63, 0xF3, 0x06, 0x12, 0x02, 0x75, + 0x31, 0xF8, 0xB1, 0x3F, + 0x02, 0x8B, 0x63, 0xF3, 0x09, 0x02, 0x02, 0x83, 0x11, 0xF8, 0x01, 0x2C, + 0x93, 0x08, 0x82, 0x7D, + 0x63, 0xF3, 0x86, 0x12, 0x82, 0x75, 0x8A, 0x78, 0xC3, 0x7D, 0x62, 0xF3, + 0x03, 0x03, 0xC3, 0x75, + 0xB1, 0xF8, 0x03, 0x30, 0xB0, 0xF8, 0x1B, 0x20, 0x63, 0xF3, 0x08, 0x02, + 0xA0, 0xF8, 0x1B, 0x20, + 0x09, 0x89, 0x41, 0x82, 0x70, 0x47, 0x00, 0x00, 0x4C, 0x07, 0x10, 0x00, + 0x00, 0xF0, 0xFF, 0xFF, + 0x00, 0x9B, 0x01, 0x20, 0xF8, 0x07, 0x10, 0x00, 0x00, 0x9D, 0x01, 0x20, + 0xE8, 0x84, 0x10, 0x00, + 0xE4, 0x9F, 0x01, 0x20, 0x40, 0x9D, 0x01, 0x20, 0x00, 0x20, 0xFF, 0xF7, + 0x1E, 0xBE, 0x70, 0x47, + 0x10, 0xB5, 0xE9, 0xF7, 0x64, 0xFF, 0x08, 0xB1, 0x01, 0x20, 0x10, 0xBD, + 0x0B, 0x48, 0xE9, 0xF7, + 0x47, 0xFF, 0x00, 0x20, 0x10, 0xBD, 0x10, 0xB5, 0x04, 0x46, 0x09, 0x48, + 0x00, 0x68, 0x90, 0xF8, + 0x70, 0x00, 0x40, 0x07, 0x01, 0xD5, 0xE9, 0xF7, 0x47, 0xFF, 0x20, 0x7B, + 0x20, 0xB1, 0x05, 0x49, + 0xEA, 0xF7, 0x12, 0xFC, 0x00, 0x20, 0x10, 0xBD, 0x01, 0x20, 0x10, 0xBD, + 0x6B, 0x6A, 0x01, 0x00, + 0x4C, 0x07, 0x10, 0x00, 0x29, 0x6E, 0x01, 0x00, 0x43, 0x48, 0x01, 0x68, + 0x21, 0xF0, 0x04, 0x01, + 0x01, 0x60, 0x70, 0x47, 0x00, 0xB5, 0xFF, 0xF7, 0xF7, 0xFF, 0x00, 0xBD, + 0x00, 0xB5, 0xFF, 0xF7, + 0xF3, 0xFF, 0x00, 0xBD, 0x00, 0xB5, 0xFF, 0xF7, 0xEF, 0xFF, 0x00, 0xBD, + 0x10, 0xB5, 0xFF, 0xF7, + 0xEB, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0xEA, 0xF7, 0x32, 0xBB, 0x10, 0xB5, + 0xFF, 0xF7, 0xE4, 0xFF, + 0xBD, 0xE8, 0x10, 0x40, 0xE9, 0xF7, 0xF8, 0xBC, 0x10, 0xB5, 0xFF, 0xF7, + 0xDD, 0xFF, 0xBD, 0xE8, + 0x10, 0x40, 0xEA, 0xF7, 0x28, 0xBC, 0x10, 0xB5, 0xFF, 0xF7, 0xD6, 0xFF, + 0xBD, 0xE8, 0x10, 0x40, + 0xEA, 0xF7, 0x66, 0xBC, 0x10, 0xB5, 0xFF, 0xF7, 0xCF, 0xFF, 0xBD, 0xE8, + 0x10, 0x40, 0xEA, 0xF7, + 0x90, 0xBC, 0x10, 0xB5, 0xFF, 0xF7, 0xC8, 0xFF, 0xBD, 0xE8, 0x10, 0x40, + 0xEA, 0xF7, 0xBA, 0xBC, + 0x10, 0xB5, 0xFF, 0xF7, 0xC1, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0xEA, 0xF7, + 0xC8, 0xBC, 0x10, 0xB5, + 0xFF, 0xF7, 0xBA, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0xEA, 0xF7, 0xE6, 0xBC, + 0x10, 0xB5, 0xFF, 0xF7, + 0xB3, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0xEA, 0xF7, 0xEF, 0xBC, 0x10, 0xB5, + 0xFF, 0xF7, 0xAC, 0xFF, + 0xBD, 0xE8, 0x10, 0x40, 0x00, 0xF0, 0xF2, 0xB9, 0x10, 0xB5, 0xFF, 0xF7, + 0xA5, 0xFF, 0xBD, 0xE8, + 0x10, 0x40, 0x00, 0xF0, 0xC7, 0xB9, 0x00, 0xB5, 0xFF, 0xF7, 0x9E, 0xFF, + 0x00, 0xBD, 0x00, 0xB5, + 0xFF, 0xF7, 0x9A, 0xFF, 0x00, 0xBD, 0x00, 0xB5, 0xFF, 0xF7, 0x96, 0xFF, + 0x00, 0xBD, 0x10, 0xB5, + 0xFF, 0xF7, 0x92, 0xFF, 0xBD, 0xE8, 0x10, 0x40, 0xEA, 0xF7, 0xFE, 0xBC, + 0x00, 0xB5, 0xFF, 0xF7, + 0x8B, 0xFF, 0x00, 0xBD, 0x00, 0xB5, 0xFF, 0xF7, 0x87, 0xFF, 0x00, 0xBD, + 0x00, 0xB5, 0xFF, 0xF7, + 0x83, 0xFF, 0x00, 0xBD, 0x00, 0xB5, 0xFF, 0xF7, 0x7F, 0xFF, 0x00, 0xBD, + 0x00, 0xB5, 0xFF, 0xF7, + 0x7B, 0xFF, 0x00, 0xBD, 0x70, 0x47, 0x00, 0x00, 0x10, 0xED, 0x00, 0xE0, + 0x10, 0xB5, 0x4A, 0xF2, + 0x33, 0x20, 0xE9, 0xF7, 0xB4, 0xFF, 0xFC, 0xF7, 0x19, 0xF8, 0xFB, 0xF7, + 0x2D, 0xFE, 0xE9, 0xF7, + 0x33, 0xFA, 0x00, 0x21, 0x47, 0x20, 0xFB, 0xF7, 0x74, 0xFA, 0x01, 0x20, + 0x10, 0xBD, 0x53, 0xEA, + 0x02, 0x0C, 0x00, 0xF0, 0x69, 0x80, 0x2D, 0xE9, 0xF0, 0x4B, 0x4F, 0xF0, + 0x00, 0x06, 0x00, 0x2B, + 0x1F, 0xBF, 0xB3, 0xFA, 0x83, 0xF5, 0x03, 0xFA, 0x05, 0xF4, 0x24, 0xFA, + 0x05, 0xF6, 0x5E, 0x40, + 0x12, 0xBF, 0x16, 0x43, 0xB2, 0xFA, 0x82, 0xF5, 0x02, 0xFA, 0x05, 0xF4, + 0xC5, 0xF1, 0x20, 0x05, + 0x1E, 0xBF, 0x22, 0xFA, 0x05, 0xFC, 0x44, 0xEA, 0x0C, 0x04, 0x20, 0x35, + 0x56, 0xEA, 0x04, 0x4C, + 0x4F, 0xEA, 0x14, 0x44, 0x18, 0xBF, 0x64, 0x1C, 0x4F, 0xF0, 0x00, 0x08, + 0x4F, 0xF0, 0x00, 0x09, + 0x90, 0x42, 0x71, 0xEB, 0x03, 0x0C, 0x39, 0xD3, 0x00, 0x29, 0x19, 0xBF, + 0xB1, 0xFA, 0x81, 0xF7, + 0x01, 0xFA, 0x07, 0xF6, 0xB0, 0xFA, 0x80, 0xF7, 0x00, 0xFA, 0x07, 0xF6, + 0xC7, 0xF1, 0x20, 0x07, + 0x1E, 0xBF, 0x20, 0xFA, 0x07, 0xFC, 0x46, 0xEA, 0x0C, 0x06, 0x20, 0x37, + 0xB6, 0xFB, 0xF4, 0xFC, + 0xA7, 0xEB, 0x05, 0x07, 0x10, 0x3F, 0x07, 0xF0, 0x1F, 0x0B, 0xCB, 0xF1, + 0x20, 0x06, 0x0C, 0xFA, + 0x0B, 0xFB, 0x2C, 0xFA, 0x06, 0xF6, 0x44, 0xBF, 0xB3, 0x46, 0x00, 0x26, + 0x20, 0x2F, 0xA4, 0xBF, + 0x5E, 0x46, 0x4F, 0xF0, 0x00, 0x0B, 0x5B, 0xEA, 0x06, 0x0C, 0x08, 0xBF, + 0x4F, 0xF0, 0x01, 0x0B, + 0x19, 0xEB, 0x0B, 0x09, 0xAB, 0xFB, 0x02, 0x7C, 0x48, 0xEB, 0x06, 0x08, + 0xC0, 0x1B, 0x06, 0xFB, + 0x02, 0xCC, 0x0B, 0xFB, 0x03, 0xCC, 0x71, 0xEB, 0x0C, 0x01, 0xC1, 0xE7, + 0x0B, 0x46, 0x02, 0x46, + 0x41, 0x46, 0x48, 0x46, 0xBD, 0xE8, 0xF0, 0x8B, 0x13, 0xB5, 0x4F, 0xF0, + 0x00, 0x00, 0x4F, 0xF0, + 0x00, 0x01, 0xAF, 0xF3, 0x00, 0x80, 0xBD, 0xE8, 0x1C, 0x40, 0x70, 0x47, + 0xB2, 0xF1, 0x20, 0x03, + 0x0A, 0xD5, 0xC2, 0xF1, 0x20, 0x03, 0x01, 0xFA, 0x02, 0xF1, 0x20, 0xFA, + 0x03, 0xF3, 0x00, 0xFA, + 0x02, 0xF0, 0x41, 0xEA, 0x03, 0x01, 0x70, 0x47, 0x00, 0xFA, 0x03, 0xF1, + 0x4F, 0xF0, 0x00, 0x00, + 0x70, 0x47, 0x10, 0xB5, 0x4C, 0x10, 0x84, 0xEA, 0x53, 0x04, 0x04, 0xD5, + 0x40, 0x42, 0xC1, 0xF1, + 0x00, 0x01, 0x38, 0xBF, 0x49, 0x1E, 0x1B, 0x42, 0x04, 0xD5, 0x52, 0x42, + 0xC3, 0xF1, 0x00, 0x03, + 0x38, 0xBF, 0x5B, 0x1E, 0xFF, 0xF7, 0x63, 0xFF, 0x14, 0xF0, 0x80, 0x4F, + 0x04, 0xD0, 0x40, 0x42, + 0xC1, 0xF1, 0x00, 0x01, 0x38, 0xBF, 0x49, 0x1E, 0x14, 0xF0, 0x00, 0x4F, + 0x04, 0xD0, 0x52, 0x42, + 0xC3, 0xF1, 0x00, 0x03, 0x38, 0xBF, 0x5B, 0x1E, 0x10, 0xBD, 0x03, 0x2A, + 0x40, 0xF2, 0x30, 0x80, + 0x10, 0xF0, 0x03, 0x0C, 0x00, 0xF0, 0x15, 0x80, 0x11, 0xF8, 0x01, 0x3B, + 0xBC, 0xF1, 0x02, 0x0F, + 0x62, 0x44, 0x98, 0xBF, 0x11, 0xF8, 0x01, 0xCB, 0x00, 0xF8, 0x01, 0x3B, + 0x38, 0xBF, 0x11, 0xF8, + 0x01, 0x3B, 0xA2, 0xF1, 0x04, 0x02, 0x98, 0xBF, 0x00, 0xF8, 0x01, 0xCB, + 0x38, 0xBF, 0x00, 0xF8, + 0x01, 0x3B, 0x11, 0xF0, 0x03, 0x03, 0x00, 0xF0, 0x25, 0x80, 0x08, 0x3A, + 0xC0, 0xF0, 0x08, 0x80, + 0x51, 0xF8, 0x04, 0x3B, 0x08, 0x3A, 0x51, 0xF8, 0x04, 0xCB, 0xA0, 0xE8, + 0x08, 0x10, 0xF5, 0xE7, + 0x12, 0x1D, 0x5C, 0xBF, 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, + 0xAF, 0xF3, 0x00, 0x80, + 0xD2, 0x07, 0x24, 0xBF, 0x11, 0xF8, 0x01, 0x3B, 0x11, 0xF8, 0x01, 0xCB, + 0x48, 0xBF, 0x11, 0xF8, + 0x01, 0x2B, 0x24, 0xBF, 0x00, 0xF8, 0x01, 0x3B, 0x00, 0xF8, 0x01, 0xCB, + 0x48, 0xBF, 0x00, 0xF8, + 0x01, 0x2B, 0x70, 0x47, 0x10, 0xB5, 0x20, 0x3A, 0xC0, 0xF0, 0x0B, 0x80, + 0xB1, 0xE8, 0x18, 0x50, + 0x20, 0x3A, 0xA0, 0xE8, 0x18, 0x50, 0xB1, 0xE8, 0x18, 0x50, 0xA0, 0xE8, + 0x18, 0x50, 0xBF, 0xF4, + 0xF5, 0xAF, 0x5F, 0xEA, 0x02, 0x7C, 0x24, 0xBF, 0xB1, 0xE8, 0x18, 0x50, + 0xA0, 0xE8, 0x18, 0x50, + 0x44, 0xBF, 0x18, 0xC9, 0x18, 0xC0, 0xBD, 0xE8, 0x10, 0x40, 0x5F, 0xEA, + 0x82, 0x7C, 0x24, 0xBF, + 0x51, 0xF8, 0x04, 0x3B, 0x40, 0xF8, 0x04, 0x3B, 0x08, 0xBF, 0x70, 0x47, + 0xD2, 0x07, 0x28, 0xBF, + 0x31, 0xF8, 0x02, 0x3B, 0x48, 0xBF, 0x11, 0xF8, 0x01, 0x2B, 0x28, 0xBF, + 0x20, 0xF8, 0x02, 0x3B, + 0x48, 0xBF, 0x00, 0xF8, 0x01, 0x2B, 0x70, 0x47, 0x02, 0xF0, 0xFF, 0x03, + 0x43, 0xEA, 0x03, 0x22, + 0x42, 0xEA, 0x02, 0x42, 0x00, 0xF0, 0x02, 0xB8, 0x4F, 0xF0, 0x00, 0x02, + 0x04, 0x29, 0xC0, 0xF0, + 0x12, 0x80, 0x10, 0xF0, 0x03, 0x0C, 0x00, 0xF0, 0x1B, 0x80, 0xCC, 0xF1, + 0x04, 0x0C, 0xBC, 0xF1, + 0x02, 0x0F, 0x18, 0xBF, 0x00, 0xF8, 0x01, 0x2B, 0xA8, 0xBF, 0x20, 0xF8, + 0x02, 0x2B, 0xA1, 0xEB, + 0x0C, 0x01, 0x00, 0xF0, 0x0D, 0xB8, 0x5F, 0xEA, 0xC1, 0x7C, 0x24, 0xBF, + 0x00, 0xF8, 0x01, 0x2B, + 0x00, 0xF8, 0x01, 0x2B, 0x48, 0xBF, 0x00, 0xF8, 0x01, 0x2B, 0x70, 0x47, + 0x4F, 0xF0, 0x00, 0x02, + 0x00, 0xB5, 0x13, 0x46, 0x94, 0x46, 0x96, 0x46, 0x20, 0x39, 0x22, 0xBF, + 0xA0, 0xE8, 0x0C, 0x50, + 0xA0, 0xE8, 0x0C, 0x50, 0xB1, 0xF1, 0x20, 0x01, 0xBF, 0xF4, 0xF7, 0xAF, + 0x09, 0x07, 0x28, 0xBF, + 0xA0, 0xE8, 0x0C, 0x50, 0x48, 0xBF, 0x0C, 0xC0, 0x5D, 0xF8, 0x04, 0xEB, + 0x89, 0x00, 0x28, 0xBF, + 0x40, 0xF8, 0x04, 0x2B, 0x08, 0xBF, 0x70, 0x47, 0x48, 0xBF, 0x20, 0xF8, + 0x02, 0x2B, 0x11, 0xF0, + 0x80, 0x4F, 0x18, 0xBF, 0x00, 0xF8, 0x01, 0x2B, 0x70, 0x47, 0x04, 0x46, + 0xAF, 0xF3, 0x00, 0x80, + 0x20, 0x46, 0xE8, 0xF7, 0x93, 0xFF, 0x00, 0x00, 0x01, 0x49, 0x18, 0x20, + 0xAB, 0xBE, 0xFE, 0xE7, + 0x26, 0x00, 0x02, 0x00, 0x70, 0x47, 0x00, 0x00, 0x01, 0x49, 0x00, 0x20, + 0x08, 0x60, 0x70, 0x47, + 0x3C, 0x05, 0x00, 0x22, 0x2D, 0xE9, 0xF0, 0x41, 0x00, 0x24, 0x01, 0x27, + 0xDF, 0xF8, 0x38, 0x80, + 0x5F, 0xEA, 0x47, 0x75, 0x07, 0xFA, 0x04, 0xF0, 0xC6, 0xB2, 0x95, 0xF8, + 0x2F, 0x00, 0x30, 0x42, + 0x0C, 0xD0, 0x95, 0xF8, 0x39, 0x00, 0x30, 0x42, 0x08, 0xD0, 0x58, 0xF8, + 0x24, 0x00, 0x00, 0xB1, + 0x80, 0x47, 0x95, 0xF8, 0x2F, 0x00, 0xB0, 0x43, 0x85, 0xF8, 0x2F, 0x00, + 0x64, 0x1C, 0x06, 0x2C, + 0xE8, 0xDB, 0xBD, 0xE8, 0xF0, 0x81, 0x00, 0x00, 0xD4, 0x0E, 0x10, 0x00, + 0x2D, 0xE9, 0xF0, 0x41, + 0x00, 0x24, 0x01, 0x27, 0xDF, 0xF8, 0x38, 0x80, 0x5F, 0xEA, 0x47, 0x75, + 0x07, 0xFA, 0x04, 0xF0, + 0xC6, 0xB2, 0x95, 0xF8, 0x2E, 0x00, 0x30, 0x42, 0x0C, 0xD0, 0x95, 0xF8, + 0x38, 0x00, 0x30, 0x42, + 0x08, 0xD0, 0x58, 0xF8, 0x24, 0x00, 0x00, 0xB1, 0x80, 0x47, 0x95, 0xF8, + 0x2E, 0x00, 0xB0, 0x43, + 0x85, 0xF8, 0x2E, 0x00, 0x64, 0x1C, 0x06, 0x2C, 0xE8, 0xDB, 0xBD, 0xE8, + 0xF0, 0x81, 0x00, 0x00, + 0xB4, 0x0E, 0x10, 0x00, 0x01, 0x21, 0x81, 0x40, 0xC8, 0xB2, 0x4F, 0xF0, + 0x00, 0x51, 0x91, 0xF8, + 0x33, 0x10, 0x01, 0x42, 0x01, 0xD0, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, + 0x70, 0x47, 0x00, 0x00, + 0x01, 0x49, 0x01, 0x20, 0x08, 0x60, 0x70, 0x47, 0x3C, 0x05, 0x00, 0x22, + 0x07, 0x48, 0x41, 0x78, + 0x49, 0xB1, 0x80, 0x78, 0x38, 0xB1, 0x06, 0x48, 0x00, 0x78, 0x01, 0x28, + 0x03, 0xD1, 0x05, 0x48, + 0x00, 0x78, 0x01, 0x28, 0x00, 0xD0, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x74, 0x07, 0x10, 0x00, + 0xFD, 0x06, 0x10, 0x00, 0x5C, 0x05, 0x10, 0x00, 0x03, 0x48, 0x41, 0x78, + 0x11, 0xB9, 0x80, 0x78, + 0x00, 0x28, 0x00, 0xD0, 0x01, 0x20, 0x70, 0x47, 0x74, 0x07, 0x10, 0x00, + 0x01, 0x48, 0x00, 0x78, + 0x70, 0x47, 0x00, 0x00, 0x74, 0x06, 0x10, 0x00, 0xC0, 0x6E, 0x70, 0x47, + 0x90, 0xF8, 0x73, 0x00, + 0x70, 0x47, 0x90, 0xF8, 0x72, 0x00, 0x70, 0x47, 0x04, 0x48, 0x41, 0x78, + 0x82, 0x78, 0x00, 0x78, + 0x11, 0x44, 0x08, 0x18, 0x00, 0xD0, 0x01, 0x20, 0x70, 0x47, 0x00, 0x00, + 0x2D, 0x06, 0x10, 0x00, + 0x70, 0xB5, 0xD0, 0xE9, 0x00, 0x21, 0x4C, 0x08, 0x4F, 0xEA, 0x32, 0x03, + 0x96, 0x18, 0x41, 0xEB, + 0x01, 0x05, 0x33, 0x43, 0x2C, 0x43, 0x13, 0x43, 0x0C, 0x43, 0xC0, 0xE9, + 0x00, 0x34, 0x70, 0xBD, + 0x01, 0xEB, 0x81, 0x01, 0x00, 0xEB, 0xC1, 0x00, 0x29, 0x30, 0x70, 0x47, + 0x02, 0x4A, 0x12, 0x78, + 0x51, 0x43, 0x00, 0xEB, 0x41, 0x00, 0x70, 0x47, 0xEE, 0x06, 0x10, 0x00, + 0x01, 0xEB, 0x81, 0x01, + 0x00, 0xEB, 0xC1, 0x00, 0x29, 0x30, 0x70, 0x47, 0x02, 0x4A, 0x12, 0x78, + 0x51, 0x43, 0x00, 0xEB, + 0x41, 0x00, 0x70, 0x47, 0xEE, 0x06, 0x10, 0x00, 0x00, 0x04, 0x40, 0x00, + 0x10, 0x21, 0x00, 0x00, + 0x00, 0x1F, 0x01, 0x00, 0x06, 0x00, 0x00, 0x00, 0x30, 0x00, 0x01, 0x00, + 0x00, 0x04, 0x06, 0x00, + 0x08, 0x02, 0x50, 0x00, 0x60, 0x02, 0x0C, 0x0C, 0x00, 0x00, 0x60, 0x02, + 0x0C, 0x30, 0x0C, 0x1A, + 0x31, 0x10, 0x0F, 0x0F, 0x00, 0x00, 0x2F, 0x00, 0x01, 0x00, 0xAA, 0x2C, + 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x18, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x60, 0x02, 0x01, 0x80, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x0C, 0x00, + 0x0C, 0x00, 0x0C, 0x00, 0x0C, 0x00, 0x07, 0x01, 0x26, 0x26, 0x12, 0x12, + 0x11, 0x00, 0x00, 0x00, + 0x00, 0x38, 0x00, 0x3C, 0x20, 0x3D, 0xD0, 0x41, 0xEC, 0x41, 0x08, 0x42, + 0x1C, 0x42, 0x30, 0x42, + 0x44, 0x42, 0x60, 0x42, 0x74, 0x42, 0x88, 0x42, 0xA4, 0x42, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, + 0x00, 0x01, 0x01, 0x02, + 0x01, 0x02, 0x02, 0x03, 0x01, 0x02, 0x02, 0x03, 0x02, 0x03, 0x03, 0x04, + 0x00, 0x00, 0x00, 0x00, + 0x1B, 0x00, 0x00, 0x80, 0x2D, 0x00, 0x00, 0x80, 0x36, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x80, + 0x5A, 0x00, 0x00, 0x00, 0x6C, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x80, + 0x99, 0x00, 0x00, 0x80, + 0x82, 0x00, 0x00, 0x00, 0xB4, 0x00, 0x00, 0x00, 0xAF, 0x00, 0x00, 0x80, + 0xD8, 0x00, 0x00, 0x00, + 0xC3, 0x00, 0x00, 0x80, 0xF5, 0x00, 0x00, 0x80, 0xEE, 0x00, 0x00, 0x00, + 0x29, 0x01, 0x00, 0x80, + 0x32, 0x01, 0x00, 0x00, 0x04, 0x01, 0x00, 0x00, 0x1F, 0x01, 0x00, 0x80, + 0x68, 0x01, 0x00, 0x00, + 0x73, 0x01, 0x00, 0x80, 0x45, 0x01, 0x00, 0x80, 0x5E, 0x01, 0x00, 0x00, + 0xB0, 0x01, 0x00, 0x00, + 0xAB, 0x01, 0x00, 0x80, 0x9D, 0x01, 0x00, 0x80, 0x86, 0x01, 0x00, 0x00, + 0xF1, 0x01, 0x00, 0x80, + 0xEA, 0x01, 0x00, 0x00, 0xDC, 0x01, 0x00, 0x00, 0xC7, 0x01, 0x00, 0x80, + 0x49, 0x02, 0x00, 0x80, + 0x52, 0x02, 0x00, 0x00, 0x64, 0x02, 0x00, 0x00, 0x7F, 0x02, 0x00, 0x80, + 0x08, 0x02, 0x00, 0x00, + 0x13, 0x02, 0x00, 0x80, 0x25, 0x02, 0x00, 0x80, 0x3E, 0x02, 0x00, 0x00, + 0xD0, 0x02, 0x00, 0x00, + 0xCB, 0x02, 0x00, 0x80, 0xFD, 0x02, 0x00, 0x80, 0xE6, 0x02, 0x00, 0x00, + 0x91, 0x02, 0x00, 0x80, + 0x8A, 0x02, 0x00, 0x00, 0xBC, 0x02, 0x00, 0x00, 0xA7, 0x02, 0x00, 0x80, + 0x60, 0x03, 0x00, 0x00, + 0x7B, 0x03, 0x00, 0x80, 0x4D, 0x03, 0x00, 0x80, 0x56, 0x03, 0x00, 0x00, + 0x21, 0x03, 0x00, 0x80, + 0x3A, 0x03, 0x00, 0x00, 0x0C, 0x03, 0x00, 0x00, 0x17, 0x03, 0x00, 0x80, + 0xF9, 0x03, 0x00, 0x80, + 0xE2, 0x03, 0x00, 0x00, 0xD4, 0x03, 0x00, 0x00, 0xCF, 0x03, 0x00, 0x80, + 0xB8, 0x03, 0x00, 0x00, + 0xA3, 0x03, 0x00, 0x80, 0x95, 0x03, 0x00, 0x80, 0x8E, 0x03, 0x00, 0x00, + 0x89, 0x04, 0x00, 0x80, + 0x92, 0x04, 0x00, 0x00, 0xA4, 0x04, 0x00, 0x00, 0xBF, 0x04, 0x00, 0x80, + 0xC8, 0x04, 0x00, 0x00, + 0xD3, 0x04, 0x00, 0x80, 0xE5, 0x04, 0x00, 0x80, 0xFE, 0x04, 0x00, 0x00, + 0x10, 0x04, 0x00, 0x00, + 0x0B, 0x04, 0x00, 0x80, 0x3D, 0x04, 0x00, 0x80, 0x26, 0x04, 0x00, 0x00, + 0x51, 0x04, 0x00, 0x80, + 0x4A, 0x04, 0x00, 0x00, 0x7C, 0x04, 0x00, 0x00, 0x67, 0x04, 0x00, 0x80, + 0xA0, 0x05, 0x00, 0x00, + 0xBB, 0x05, 0x00, 0x80, 0x8D, 0x05, 0x00, 0x80, 0x96, 0x05, 0x00, 0x00, + 0xE1, 0x05, 0x00, 0x80, + 0xFA, 0x05, 0x00, 0x00, 0xCC, 0x05, 0x00, 0x00, 0xD7, 0x05, 0x00, 0x80, + 0x39, 0x05, 0x00, 0x80, + 0x22, 0x05, 0x00, 0x00, 0x14, 0x05, 0x00, 0x00, 0x0F, 0x05, 0x00, 0x80, + 0x78, 0x05, 0x00, 0x00, + 0x63, 0x05, 0x00, 0x80, 0x55, 0x05, 0x00, 0x80, 0x4E, 0x05, 0x00, 0x00, + 0xC0, 0x06, 0x00, 0x00, + 0xDB, 0x06, 0x00, 0x80, 0xED, 0x06, 0x00, 0x80, 0xF6, 0x06, 0x00, 0x00, + 0x81, 0x06, 0x00, 0x80, + 0x9A, 0x06, 0x00, 0x00, 0xAC, 0x06, 0x00, 0x00, 0xB7, 0x06, 0x00, 0x80, + 0x59, 0x06, 0x00, 0x80, + 0x42, 0x06, 0x00, 0x00, 0x74, 0x06, 0x00, 0x00, 0x6F, 0x06, 0x00, 0x80, + 0x18, 0x06, 0x00, 0x00, + 0x03, 0x06, 0x00, 0x80, 0x35, 0x06, 0x00, 0x80, 0x2E, 0x06, 0x00, 0x00, + 0xE9, 0x07, 0x00, 0x80, + 0xF2, 0x07, 0x00, 0x00, 0xC4, 0x07, 0x00, 0x00, 0xDF, 0x07, 0x00, 0x80, + 0xA8, 0x07, 0x00, 0x00, + 0xB3, 0x07, 0x00, 0x80, 0x85, 0x07, 0x00, 0x80, 0x9E, 0x07, 0x00, 0x00, + 0x70, 0x07, 0x00, 0x00, + 0x6B, 0x07, 0x00, 0x80, 0x5D, 0x07, 0x00, 0x80, 0x46, 0x07, 0x00, 0x00, + 0x31, 0x07, 0x00, 0x80, + 0x2A, 0x07, 0x00, 0x00, 0x1C, 0x07, 0x00, 0x00, 0x07, 0x07, 0x00, 0x80, + 0x09, 0x09, 0x00, 0x80, + 0x12, 0x09, 0x00, 0x00, 0x24, 0x09, 0x00, 0x00, 0x3F, 0x09, 0x00, 0x80, + 0x48, 0x09, 0x00, 0x00, + 0x53, 0x09, 0x00, 0x80, 0x65, 0x09, 0x00, 0x80, 0x7E, 0x09, 0x00, 0x00, + 0x90, 0x09, 0x00, 0x00, + 0x8B, 0x09, 0x00, 0x80, 0xBD, 0x09, 0x00, 0x80, 0xA6, 0x09, 0x00, 0x00, + 0xD1, 0x09, 0x00, 0x80, + 0xCA, 0x09, 0x00, 0x00, 0xFC, 0x09, 0x00, 0x00, 0xE7, 0x09, 0x00, 0x80, + 0x20, 0x08, 0x00, 0x00, + 0x3B, 0x08, 0x00, 0x80, 0x0D, 0x08, 0x00, 0x80, 0x16, 0x08, 0x00, 0x00, + 0x61, 0x08, 0x00, 0x80, + 0x7A, 0x08, 0x00, 0x00, 0x4C, 0x08, 0x00, 0x00, 0x57, 0x08, 0x00, 0x80, + 0xB9, 0x08, 0x00, 0x80, + 0xA2, 0x08, 0x00, 0x00, 0x94, 0x08, 0x00, 0x00, 0x8F, 0x08, 0x00, 0x80, + 0xF8, 0x08, 0x00, 0x00, + 0xE3, 0x08, 0x00, 0x80, 0xD5, 0x08, 0x00, 0x80, 0xCE, 0x08, 0x00, 0x00, + 0x40, 0x0B, 0x00, 0x00, + 0x5B, 0x0B, 0x00, 0x80, 0x6D, 0x0B, 0x00, 0x80, 0x76, 0x0B, 0x00, 0x00, + 0x01, 0x0B, 0x00, 0x80, + 0x1A, 0x0B, 0x00, 0x00, 0x2C, 0x0B, 0x00, 0x00, 0x37, 0x0B, 0x00, 0x80, + 0xD9, 0x0B, 0x00, 0x80, + 0xC2, 0x0B, 0x00, 0x00, 0xF4, 0x0B, 0x00, 0x00, 0xEF, 0x0B, 0x00, 0x80, + 0x98, 0x0B, 0x00, 0x00, + 0x83, 0x0B, 0x00, 0x80, 0xB5, 0x0B, 0x00, 0x80, 0xAE, 0x0B, 0x00, 0x00, + 0x69, 0x0A, 0x00, 0x80, + 0x72, 0x0A, 0x00, 0x00, 0x44, 0x0A, 0x00, 0x00, 0x5F, 0x0A, 0x00, 0x80, + 0x28, 0x0A, 0x00, 0x00, + 0x33, 0x0A, 0x00, 0x80, 0x05, 0x0A, 0x00, 0x80, 0x1E, 0x0A, 0x00, 0x00, + 0xF0, 0x0A, 0x00, 0x00, + 0xEB, 0x0A, 0x00, 0x80, 0xDD, 0x0A, 0x00, 0x80, 0xC6, 0x0A, 0x00, 0x00, + 0xB1, 0x0A, 0x00, 0x80, + 0xAA, 0x0A, 0x00, 0x00, 0x9C, 0x0A, 0x00, 0x00, 0x87, 0x0A, 0x00, 0x80, + 0x80, 0x0D, 0x00, 0x00, + 0x9B, 0x0D, 0x00, 0x80, 0xAD, 0x0D, 0x00, 0x80, 0xB6, 0x0D, 0x00, 0x00, + 0xC1, 0x0D, 0x00, 0x80, + 0xDA, 0x0D, 0x00, 0x00, 0xEC, 0x0D, 0x00, 0x00, 0xF7, 0x0D, 0x00, 0x80, + 0x19, 0x0D, 0x00, 0x80, + 0x02, 0x0D, 0x00, 0x00, 0x34, 0x0D, 0x00, 0x00, 0x2F, 0x0D, 0x00, 0x80, + 0x58, 0x0D, 0x00, 0x00, + 0x43, 0x0D, 0x00, 0x80, 0x75, 0x0D, 0x00, 0x80, 0x6E, 0x0D, 0x00, 0x00, + 0xA9, 0x0C, 0x00, 0x80, + 0xB2, 0x0C, 0x00, 0x00, 0x84, 0x0C, 0x00, 0x00, 0x9F, 0x0C, 0x00, 0x80, + 0xE8, 0x0C, 0x00, 0x00, + 0xF3, 0x0C, 0x00, 0x80, 0xC5, 0x0C, 0x00, 0x80, 0xDE, 0x0C, 0x00, 0x00, + 0x30, 0x0C, 0x00, 0x00, + 0x2B, 0x0C, 0x00, 0x80, 0x1D, 0x0C, 0x00, 0x80, 0x06, 0x0C, 0x00, 0x00, + 0x71, 0x0C, 0x00, 0x80, + 0x6A, 0x0C, 0x00, 0x00, 0x5C, 0x0C, 0x00, 0x00, 0x47, 0x0C, 0x00, 0x80, + 0xC9, 0x0F, 0x00, 0x80, + 0xD2, 0x0F, 0x00, 0x00, 0xE4, 0x0F, 0x00, 0x00, 0xFF, 0x0F, 0x00, 0x80, + 0x88, 0x0F, 0x00, 0x00, + 0x93, 0x0F, 0x00, 0x80, 0xA5, 0x0F, 0x00, 0x80, 0xBE, 0x0F, 0x00, 0x00, + 0x50, 0x0F, 0x00, 0x00, + 0x4B, 0x0F, 0x00, 0x80, 0x7D, 0x0F, 0x00, 0x80, 0x66, 0x0F, 0x00, 0x00, + 0x11, 0x0F, 0x00, 0x80, + 0x0A, 0x0F, 0x00, 0x00, 0x3C, 0x0F, 0x00, 0x00, 0x27, 0x0F, 0x00, 0x80, + 0xE0, 0x0E, 0x00, 0x00, + 0xFB, 0x0E, 0x00, 0x80, 0xCD, 0x0E, 0x00, 0x80, 0xD6, 0x0E, 0x00, 0x00, + 0xA1, 0x0E, 0x00, 0x80, + 0xBA, 0x0E, 0x00, 0x00, 0x8C, 0x0E, 0x00, 0x00, 0x97, 0x0E, 0x00, 0x80, + 0x79, 0x0E, 0x00, 0x80, + 0x62, 0x0E, 0x00, 0x00, 0x54, 0x0E, 0x00, 0x00, 0x4F, 0x0E, 0x00, 0x80, + 0x38, 0x0E, 0x00, 0x00, + 0x23, 0x0E, 0x00, 0x80, 0x15, 0x0E, 0x00, 0x80, 0x0E, 0x0E, 0x00, 0x00, + 0xFF, 0x00, 0xBE, 0x94, + 0xFE, 0xFF, 0x27, 0xC4, 0xFE, 0xFF, 0x59, 0xF2, 0xFE, 0xFF, 0x6B, 0x1F, + 0xFF, 0xFF, 0x81, 0x4B, + 0xFF, 0xFF, 0xC5, 0x76, 0xFF, 0xFF, 0x67, 0xA1, 0xFF, 0xFF, 0x97, 0xCB, + 0xFF, 0xFF, 0x88, 0xF5, + 0xFF, 0xFF, 0x6C, 0x1F, 0x00, 0x00, 0x76, 0x49, 0x00, 0x00, 0xD9, 0x73, + 0x00, 0x00, 0xC6, 0x9E, + 0x00, 0x00, 0x6D, 0xCA, 0x00, 0x00, 0xFC, 0xF6, 0x00, 0x00, 0x9A, 0x24, + 0x01, 0x00, 0x66, 0x53, + 0x01, 0x00, 0xA3, 0x8D, 0x00, 0x00, 0x71, 0x74, 0x00, 0x00, 0x02, 0x60, + 0x00, 0x00, 0xA2, 0x4F, + 0x00, 0x00, 0xC8, 0x42, 0x00, 0x00, 0x0C, 0x39, 0x00, 0x00, 0x21, 0x32, + 0x00, 0x00, 0xD2, 0x2D, + 0x00, 0x00, 0x00, 0x2C, 0x00, 0x00, 0x9B, 0x2C, 0x00, 0x00, 0xA9, 0x2F, + 0x00, 0x00, 0x40, 0x35, + 0x00, 0x00, 0x8B, 0x3D, 0x00, 0x00, 0xCB, 0x48, 0x00, 0x00, 0x59, 0x57, + 0x00, 0x00, 0xAD, 0x69, + 0x00, 0x00, 0x65, 0x80, 0x00, 0x00, 0x30, 0x11, 0x00, 0x00, 0x4C, 0x1C, + 0x00, 0x00, 0x2D, 0x29, + 0x00, 0x00, 0x86, 0x37, 0x00, 0x00, 0x24, 0x47, 0x00, 0x00, 0xE8, 0x57, + 0x00, 0x00, 0xC4, 0x69, + 0x00, 0x00, 0xB5, 0x7C, 0x00, 0x00, 0xC4, 0x90, 0x00, 0x00, 0x03, 0xA6, + 0x00, 0x00, 0x8F, 0xBC, + 0x00, 0x00, 0x8C, 0xD4, 0x00, 0x00, 0x29, 0xEE, 0x00, 0x00, 0x9C, 0x09, + 0x01, 0x00, 0x2B, 0x27, + 0x01, 0x00, 0x24, 0x47, 0x01, 0x00, 0xE6, 0x69, 0x01, 0x00, 0x98, 0x08, + 0x00, 0x00, 0x26, 0x0E, + 0x00, 0x00, 0x97, 0x14, 0x00, 0x00, 0xC3, 0x1B, 0x00, 0x00, 0x92, 0x23, + 0x00, 0x00, 0xF4, 0x2B, + 0x00, 0x00, 0xE2, 0x34, 0x00, 0x00, 0x5A, 0x3E, 0x00, 0x00, 0x62, 0x48, + 0x00, 0x00, 0x02, 0x53, + 0x00, 0x00, 0x48, 0x5E, 0x00, 0x00, 0x46, 0x6A, 0x00, 0x00, 0x14, 0x77, + 0x00, 0x00, 0xCE, 0x84, + 0x00, 0x00, 0x95, 0x93, 0x00, 0x00, 0x92, 0xA3, 0x00, 0x00, 0xF3, 0xB4, + 0x00, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00, + 0x02, 0x00, 0x01, 0x00, + 0x10, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x14, 0x00, + 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0x0C, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xF8, 0x47, 0x10, 0x00, 0x44, 0x4D, 0x10, 0x00, 0xC5, 0x18, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xC3, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD1, 0x17, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xDF, 0x17, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xE3, 0x17, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x09, 0x18, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x6B, 0x18, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x81, 0x18, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xB5, 0x18, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xB7, 0x18, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xB9, 0x18, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xBB, 0x18, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xBD, 0x18, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0xBF, 0x18, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xC1, 0x18, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xC3, 0x18, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0x18, 0x01, 0x00, + 0xFB, 0x18, 0x01, 0x00, + 0x65, 0x19, 0x01, 0x00, 0xFB, 0x18, 0x01, 0x00, 0x17, 0x1A, 0x01, 0x00, + 0xFB, 0x18, 0x01, 0x00, + 0xFB, 0x18, 0x01, 0x00, 0xFB, 0x18, 0x01, 0x00, 0xFB, 0x18, 0x01, 0x00, + 0xFB, 0x18, 0x01, 0x00, + 0x2F, 0x19, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFB, 0x18, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x61, 0x19, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x91, 0x19, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xB5, 0x19, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xD9, 0x19, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x0F, 0x1A, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0x13, 0x1A, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x43, 0x1A, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x91, 0x1A, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0xA7, 0x1A, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0xFF, 0x1A, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0xB5, 0x1B, 0x01, 0x00, 0x02, 0x00, 0x00, 0x00, 0x33, 0x1C, 0x01, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x73, 0x1C, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x65, 0x1B, 0x01, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0xFB, 0x18, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFB, 0x18, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x5D, 0x1A, 0x01, 0x00, 0x67, 0x1A, 0x01, 0x00, 0x71, 0x1A, 0x01, 0x00, + 0x81, 0x1A, 0x01, 0x00, + 0xF5, 0x1D, 0x01, 0x00, 0x17, 0x1E, 0x01, 0x00, 0x1F, 0x1E, 0x01, 0x00, + 0x3F, 0x1E, 0x01, 0x00, + 0xA1, 0x1E, 0x01, 0x00, 0xB7, 0x1E, 0x01, 0x00, 0xC7, 0x1E, 0x01, 0x00, + 0xD9, 0x1E, 0x01, 0x00, + 0xEB, 0x1E, 0x01, 0x00, 0xFD, 0x1E, 0x01, 0x00, 0x0F, 0x1F, 0x01, 0x00, + 0x21, 0x1F, 0x01, 0x00, + 0x33, 0x1F, 0x01, 0x00, 0x45, 0x1F, 0x01, 0x00, 0x57, 0x1F, 0x01, 0x00, + 0x69, 0x1F, 0x01, 0x00, + 0x85, 0x86, 0x60, 0x61, 0xD0, 0x02, 0x0F, 0x01, 0x00, 0xA6, 0x02, 0x0F, + 0x01, 0x00, 0xA8, 0x02, + 0x0B, 0x03, 0x00, 0x72, 0x00, 0x0B, 0x01, 0x00, 0x73, 0x00, 0x08, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x49, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4D, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x53, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xF3, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0xE3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, + 0x04, 0x69, 0x10, 0x00, 0x00, 0x04, 0x00, 0x00, 0xB5, 0x4E, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x04, 0x6D, 0x10, 0x00, + 0x00, 0x04, 0x00, 0x00, 0xDD, 0x5E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x04, 0x71, 0x10, 0x00, + 0x00, 0x08, 0x00, 0x00, + 0x8F, 0x15, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x04, 0x79, 0x10, 0x00, 0x00, 0x02, 0x00, 0x00, + 0x01, 0x1D, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x04, 0x7B, 0x10, 0x00, 0x80, 0x00, 0x00, 0x00, 0xB9, 0x16, 0x01, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, + 0x02, 0x00, 0x00, 0x00, + 0x03, 0x00, 0x00, 0x00, 0xB1, 0x56, 0x01, 0x00, 0x5B, 0x56, 0x01, 0x00, + 0x31, 0x6E, 0x01, 0x00, + 0x23, 0x5B, 0x01, 0x00, 0x65, 0x48, 0x01, 0x00, 0x9B, 0x5D, 0x01, 0x00, + 0x8F, 0x4D, 0x01, 0x00, + 0x73, 0x68, 0x01, 0x00, 0xF1, 0x4E, 0x01, 0x00, 0x4D, 0x57, 0x01, 0x00, + 0x47, 0x6E, 0x01, 0x00, + 0x60, 0x7D, 0x01, 0x00, 0x00, 0x04, 0x10, 0x00, 0x0C, 0x04, 0x00, 0x00, + 0x1C, 0x01, 0x00, 0x00, + 0x98, 0x7D, 0x01, 0x00, 0x00, 0xFC, 0x10, 0x00, 0x40, 0x00, 0x00, 0x00, + 0x78, 0x01, 0x00, 0x00, + 0x98, 0x7D, 0x01, 0x00, 0x0C, 0x08, 0x10, 0x00, 0x88, 0x7D, 0x00, 0x00, + 0x94, 0x01, 0x00, 0x00, + 0x01, 0x29, 0x04, 0xFF, 0x90, 0xD0, 0x03, 0x01, 0x71, 0x14, 0x90, 0x5F, + 0x01, 0x32, 0x01, 0x32, + 0x02, 0x29, 0x08, 0x41, 0xA9, 0x08, 0x09, 0x1A, 0x0C, 0xB2, 0x64, 0x29, + 0x0C, 0x69, 0x48, 0x29, + 0x04, 0x0A, 0x11, 0x04, 0x10, 0x01, 0xFF, 0x01, 0x46, 0x07, 0xA5, 0xF0, + 0x01, 0x20, 0x18, 0x50, + 0x10, 0xAA, 0xFF, 0x0C, 0x59, 0x01, 0x00, 0x00, 0x30, 0xB5, 0x72, 0xB6, + 0x01, 0x24, 0x0C, 0x4D, + 0x2C, 0x60, 0x0C, 0x4B, 0x00, 0x22, 0x89, 0xB1, 0xC3, 0xF8, 0x00, 0x40, + 0x4F, 0xF0, 0x00, 0x51, + 0x00, 0xF0, 0x1F, 0x00, 0x81, 0xF8, 0x6A, 0x00, 0x06, 0x48, 0x1C, 0x38, + 0x04, 0x60, 0x01, 0x68, + 0x00, 0x29, 0xFC, 0xD1, 0x1A, 0x60, 0x2A, 0x60, 0x62, 0xB6, 0x30, 0xBD, + 0x1A, 0x60, 0xED, 0xE7, + 0xC0, 0x1B, 0x00, 0x22, 0x78, 0x0D, 0x00, 0x22, 0xD5, 0xA1, 0xA1, 0x0A, + 0x93, 0x02, 0x00, 0x00, + 0x2A, 0x5E, 0x5E, 0xF5, 0x6C, 0xFD, 0xFF, 0xFF, 0xA1, 0x00, 0xA1, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0x3F, + 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x7F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1E, 0x0F, 0xFF, 0x09, + 0x9F, 0x05, 0x09, 0xFF, + 0x09, 0x9F, 0x05, 0x1D, 0x02, 0x00, 0x00, 0x00, 0x01, 0x20, 0x40, 0x50, + 0xAA, 0x99, 0xC8, 0x00, + 0xC8, 0x00, 0xC8, 0x00, 0xC8, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, + 0x00, 0x01, 0x70, 0x00, + 0x70, 0x00, 0x08, 0xB0, 0x00, 0xB0, 0x00, 0x00, 0x07, 0xAA, 0x38, 0xC8, + 0x00, 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x08, 0x09, 0x0A, + 0x14, 0x0A, 0x00, 0x02, + 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x13, 0xE8, 0x03, + 0x64, 0x00, 0x64, 0x00, + 0xD0, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82, 0x00, 0x00, 0x64, + 0x00, 0x00, 0x00, 0xFF, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x08, 0x00, 0x02, + 0x08, 0x00, 0x06, 0x00, + 0x00, 0x00, 0x00, 0x08, 0x41, 0x01, 0x08, 0x00, 0x13, 0x0C, 0x41, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x81, 0x06, 0x52, 0x4F, 0x04, 0xD8, 0x10, 0x50, 0x00, 0x2F, 0x00, 0x08, + 0xB0, 0x06, 0x03, 0x03, + 0x00, 0x00, 0xBB, 0xBB, 0x00, 0x00, 0x01, 0xFF, 0xFF, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE9, 0xA6, + 0x5E, 0x1F, 0x04, 0xD8, 0x18, 0x40, 0x00, 0x08, 0x00, 0x20, 0x50, 0x06, + 0x07, 0x00, 0x00, 0x00, + 0x20, 0x50, 0x06, 0x07, 0x00, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x20, + 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x89, 0x16, + 0x50, 0x4F, 0x04, 0x18, + 0x00, 0x30, 0x00, 0x06, 0x00, 0x2F, 0x00, 0x40, 0x10, 0x06, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x26, + 0x9A, 0x1F, 0x98, 0x18, + 0x01, 0x01, 0x30, 0x00, 0x60, 0x00, 0x60, 0x00, 0x2F, 0x00, 0x21, 0x01, + 0x00, 0x00, 0x1F, 0x21, + 0x01, 0x00, 0x00, 0x1F, 0x00, 0x01, 0x20, 0x00, 0x99, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xB8, 0x0B, + 0x00, 0x00, 0x00, 0x00, + 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x1A, + 0x00, 0x00, 0x02, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x1A, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x11, 0x1A, 0x00, 0x00, 0x02, 0x00, 0x01, 0x01, 0x64, 0x00, + 0x64, 0x00, 0xD0, 0x00, + 0x80, 0x0C, 0xF0, 0x0A, 0xD0, 0x00, 0x00, 0x15, 0x00, 0x12, 0x50, 0x01, + 0x50, 0x01, 0x00, 0x15, + 0x00, 0x12, 0x50, 0x01, 0x80, 0x0C, 0xF0, 0x0A, 0xD0, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x0F, 0x00, 0x06, + 0x0A, 0x0F, 0x02, 0x64, + 0x90, 0x01, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0x0F, 0xFF, 0x0F, + 0x14, 0x14, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x02, 0x64, 0x90, 0x01, 0x90, 0x01, 0x80, 0x00, 0x80, 0x00, 0xF4, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x00, 0x64, 0x00, + 0x80, 0x01, 0x64, 0x00, + 0x80, 0x01, 0x96, 0x00, 0x64, 0x00, 0x20, 0x00, 0x02, 0x00, 0x96, 0x00, + 0x64, 0x00, 0x64, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, 0x00, 0x05, 0x01, 0xF4, 0x01, + 0x2C, 0x01, 0x02, 0xFF, + 0x7F, 0xFF, 0x7F, 0x02, 0x32, 0x64, 0x00, 0x00, 0x02, 0x02, 0xA2, 0x30, + 0x29, 0x64, 0x00, 0x64, + 0x00, 0xC8, 0x00, 0x58, 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x64, 0x00, + 0x32, 0x00, 0x01, 0x00, + 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x05, 0x00, 0x04, 0x00, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, 0x02, 0x10, 0x00, + 0x20, 0x00, 0x18, 0x00, + 0x00, 0x01, 0x62, 0x84, 0x40, 0x01, 0x20, 0x00, 0x10, 0x00, 0x64, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x00, 0x20, 0x00, + 0x40, 0x2C, 0x7D, 0x00, + 0x2C, 0x01, 0x64, 0x00, 0x00, 0x0A, 0x00, 0x0F, 0x00, 0x0F, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2C, 0x01, 0x64, 0x00, + 0x2C, 0x01, 0x00, 0x20, + 0x02, 0x01, 0x00, 0x00, 0x00, 0x00, 0x56, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 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, 0x5A, 0x00, + 0x14, 0x00, 0x01, 0x03, + 0x01, 0x0A, 0x00, 0x10, 0x11, 0x11, 0x00, 0x00, 0x00, 0x02, 0x00, 0x02, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x50, 0x00, + 0x70, 0x00, 0x32, 0x00, + 0x40, 0x00, 0x00, 0x00, 0xC8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x01, + 0x00, 0x02, 0x00, 0x02, + 0x00, 0x02, 0x64, 0x00, 0x0A, 0x64, 0x00, 0x64, 0x00, 0x0E, 0x00, 0x05, + 0x00, 0x10, 0xC2, 0x00, + 0x32, 0x00, 0x20, 0x31, 0x0F, 0x02, 0x20, 0x1F, 0x00, 0x0A, 0x00, 0x14, + 0x92, 0x11, 0x15, 0x00, + 0x13, 0x00, 0x02, 0x10, 0x0A, 0x00, 0x40, 0x00, 0x00, 0x40, 0x00, 0x10, + 0xE8, 0x10, 0x00, 0x40, + 0x00, 0x62, 0x94, 0x94, 0x28, 0xF4, 0x0A, 0x00, 0x18, 0x00, 0x10, 0x00, + 0x30, 0x00, 0x05, 0x14, + 0x05, 0x20, 0x03, 0x10, 0xD8, 0x05, 0x32, 0xF8, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x03, 0xC8, 0x00, + 0xC8, 0x00, 0x0A, 0x0A, + 0x20, 0x00, 0x64, 0x00, 0x01, 0x03, 0x64, 0x00, 0x64, 0x00, 0x01, 0x03, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0E, 0x00, 0x40, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x08, 0x32, 0x1A, 0xFA, 0x00, 0x0A, 0x05, 0x20, 0x0A, 0x05, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x0A, 0x00, 0x14, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x03, 0x50, 0x00, + 0x2C, 0x01, 0x32, 0xFF, + 0x7F, 0x0B, 0x01, 0x32, 0x00, 0x20, 0x03, 0x00, 0x0A, 0x20, 0x14, 0x05, + 0xF8, 0x00, 0x00, 0x00, + 0x00, 0x00, 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, 0x02, + 0x03, 0x04, 0x00, 0x01, + 0x02, 0x03, 0x50, 0x01, 0x50, 0x01, 0x50, 0x01, 0x50, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x96, 0x7D, 0x6E, 0x67, + 0x65, 0x64, 0x64, 0x64, + 0x64, 0x64, 0x64, 0x64, 0x64, 0x65, 0x67, 0x6E, 0x7D, 0x96, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x0F, 0x13, 0x22, 0x22, 0x22, 0x00, 0x00, 0x0F, 0x00, 0x28, 0x00, 0x3C, + 0x00, 0x50, 0x00, 0xA0, + 0x00, 0x40, 0x01, 0xE0, 0x01, 0xD0, 0x02, 0xBF, 0x03, 0x5F, 0x04, 0xFF, + 0x04, 0x4F, 0x05, 0x63, + 0x05, 0x77, 0x05, 0x90, 0x05, 0x0F, 0x00, 0x28, 0x00, 0x3C, 0x00, 0x50, + 0x00, 0xA0, 0x00, 0x40, + 0x01, 0xE0, 0x01, 0xD0, 0x02, 0xC0, 0x03, 0x00, 0x05, 0x3F, 0x06, 0x2F, + 0x07, 0x1F, 0x08, 0xBF, + 0x08, 0x5F, 0x09, 0xAF, 0x09, 0xC3, 0x09, 0xD7, 0x09, 0xF5, 0x09, 0x00, + 0x00, 0x0A, 0x00, 0x19, + 0x00, 0x28, 0x00, 0x6C, 0x00, 0x27, 0x01, 0xD1, 0x01, 0xD0, 0x02, 0xC6, + 0x03, 0x72, 0x04, 0x21, + 0x05, 0x69, 0x05, 0x86, 0x05, 0x95, 0x05, 0x9F, 0x05, 0x00, 0x00, 0x0F, + 0x00, 0x1C, 0x00, 0x28, + 0x00, 0x78, 0x00, 0x1C, 0x01, 0xC6, 0x01, 0xBE, 0x02, 0xAE, 0x03, 0x00, + 0x05, 0x4F, 0x06, 0x44, + 0x07, 0x39, 0x08, 0xDE, 0x08, 0x8A, 0x09, 0xD8, 0x09, 0xE3, 0x09, 0xF1, + 0x09, 0xFF, 0x09, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x64, 0x00, 0x64, 0x00, + 0x00, 0x00, 0x64, 0x80, + 0x10, 0xE5, 0x00, 0x00, 0x64, 0x80, 0x40, 0x00, 0x80, 0x00, 0xC0, 0x00, + 0x00, 0x01, 0x40, 0x01, + 0x80, 0x01, 0xC0, 0x01, 0x00, 0x02, 0x40, 0x02, 0x80, 0x02, 0xC0, 0x02, + 0x00, 0x03, 0x40, 0x03, + 0x80, 0x03, 0xC0, 0x03, 0x00, 0x04, 0x3F, 0x04, 0x7F, 0x04, 0xBF, 0x04, + 0xFF, 0x04, 0x3F, 0x05, + 0x7F, 0x05, 0xBF, 0x05, 0xFF, 0x05, 0x3F, 0x06, 0x7F, 0x06, 0xBF, 0x06, + 0xFF, 0x06, 0x3F, 0x07, + 0x7F, 0x07, 0xBF, 0x07, 0xFF, 0x07, 0xFF, 0x07, 0xBF, 0x07, 0x7F, 0x07, + 0x3F, 0x07, 0xFF, 0x06, + 0xBF, 0x06, 0x7F, 0x06, 0x3F, 0x06, 0xFF, 0x05, 0xBF, 0x05, 0x7F, 0x05, + 0x3F, 0x05, 0xFF, 0x04, + 0xBF, 0x04, 0x7F, 0x04, 0x3F, 0x04, 0x00, 0x04, 0xC0, 0x03, 0x80, 0x03, + 0x40, 0x03, 0x00, 0x03, + 0xC0, 0x02, 0x80, 0x02, 0x40, 0x02, 0x00, 0x02, 0xC0, 0x01, 0x80, 0x01, + 0x40, 0x01, 0x00, 0x01, + 0xC0, 0x00, 0x80, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 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, 0x00, 0x40, 0x00, 0x60, 0x00, + 0x80, 0x00, 0xA0, 0x00, + 0xC0, 0x00, 0xE0, 0x00, 0x00, 0x01, 0x00, 0x01, 0xE0, 0x00, 0xC0, 0x00, + 0xA0, 0x00, 0x80, 0x00, + 0x60, 0x00, 0x40, 0x00, 0x20, 0x00, 0x14, 0x05, 0x14, 0x05, 0x14, 0x05, + 0x14, 0x05, 0x14, 0x05, + 0x14, 0x05, 0x14, 0x05, 0x14, 0x05, 0x14, 0x05, 0x14, 0x05, 0x14, 0x05, + 0x14, 0x05, 0x14, 0x05, + 0x14, 0x05, 0x14, 0x05, 0x14, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, 0x00, 0x03, + 0x00, 0x03, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x04, 0x20, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 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, 0x00, 0xCD, 0x00, 0xCD, 0x00, + 0xCD, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x07, + 0x08, 0x0C, 0x0D, 0x0F, + 0x0F, 0x0F, 0x0E, 0x0E, 0x0E, 0x0D, 0x0D, 0x0D, 0x0A, 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, 0xA9, 0x64, + 0x9A, 0x1F, 0x18, 0x18, + 0x01, 0x01, 0x30, 0x00, 0x60, 0x00, 0x60, 0x00, 0x2F, 0x00, 0x21, 0x01, + 0x00, 0x00, 0x1F, 0x20, + 0x01, 0x00, 0x00, 0x1F, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, + 0x98, 0x24, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x50, 0x46, 0x50, 0x10, + 0x10, 0xB0, 0x20, 0xFF, + 0xD0, 0x00, 0x06, 0x14, 0x14, 0x2A, 0x3A, 0x40, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x14, 0x6E, 0x6E, 0x47, 0x1A, 0x38, 0x00, 0x00, 0x00, 0x01, 0x0F, + 0x1E, 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, 0xA9, 0x24, + 0x94, 0x1F, 0x18, 0x18, + 0x01, 0x00, 0x25, 0x00, 0x25, 0x00, 0x50, 0x00, 0x24, 0x00, 0x70, 0x01, + 0x00, 0x00, 0x1F, 0x80, + 0x01, 0x00, 0x00, 0x1F, 0x00, 0x01, 0x10, 0x00, 0x55, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x1C, 0x00, 0x00, 0x00, 0x00, 0x88, 0x88, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x75, 0x6A, 0xB0, +}; + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/Makefile b/drivers/input/touchscreen/fts_521/fts_lib/Makefile new file mode 100644 index 000000000000..ca95cb0289ed --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/Makefile @@ -0,0 +1,7 @@ +# +# Makefile for the FTS touchscreen driver. +# + + +obj-$(CONFIG_TOUCHSCREEN_ST_FTS_V521) += ftsCompensation.o ftsCore.o ftsError.o ftsFrame.o ftsIO.o ftsTest.o ftsTime.o ftsTool.o ftsFlash.o ftsGesture.o + diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsCompensation.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsCompensation.c new file mode 100644 index 000000000000..22421710b2f3 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsCompensation.c @@ -0,0 +1,790 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS functions for getting Initialization Data * +* * +************************************************************************** +************************************************************************** + +*/ +/*! +* \file ftsCompensation.c +* \brief Contains all the function to work with Initialization Data +*/ + +#include "ftsCompensation.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsFrame.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTime.h" +#include "ftsTool.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** +* Request to the FW to load the specified Initialization Data +* @param type type of Initialization data to load @link load_opt Load Host Data Option @endlink +* @return OK if success or an error code which specify the type of error encountered +*/ +int requestCompensationData(u8 type) +{ + int ret = ERROR_OP_NOT_ALLOW; + int retry = 0; + + logError(0, "%s %s: Requesting compensation data... \n", tag, __func__, + retry + 1); + while (retry < RETRY_COMP_DATA_READ) { + ret = writeSysCmd(SYS_CMD_LOAD_DATA, &type, 1); + if (ret < OK) { + logError(1, "%s %s: failed at %d attemp! \n", tag, + __func__, retry + 1); + retry += 1; + } else { + logError(0, + "%s %s: Request Compensation data FINISHED! \n", + tag, __func__); + return OK; + } + } + + logError(1, "%s %s: Requesting compensation data... ERROR %08X \n", tag, + __func__, ret | ERROR_REQU_COMP_DATA); + return ret | ERROR_REQU_COMP_DATA; + +} + +/** +* Read Initialization Data Header and check that the type loaded match with the one previously requested +* @param type type of Initialization data requested @link load_opt Load Host Data Option @endlink +* @param header pointer to DataHeader variable which will contain the header +* @param address pointer to a variable which will contain the updated address to the next data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readCompensationDataHeader(u8 type, DataHeader *header, u64 *address) +{ + + u64 offset = ADDR_FRAMEBUFFER; + u8 data[COMP_DATA_HEADER]; + int ret; + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, offset, data, + COMP_DATA_HEADER, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, + "%s %s: error while reading data header ERROR %08X \n", + tag, __func__, ret); + return ret; + } + + logError(0, "%s Read Data Header done! \n", tag); + + if (data[0] != HEADER_SIGNATURE) { + logError(1, + "%s %s: The Header Signature was wrong! %02X != %02X ERROR %08X \n", + tag, __func__, data[0], HEADER_SIGNATURE, + ERROR_WRONG_DATA_SIGN); + return ERROR_WRONG_DATA_SIGN; + } + + if (data[1] != type) { + logError(1, "%s %s: Wrong type found! %02X!=%02X ERROR %08X\n", + tag, __func__, data[1], type, ERROR_DIFF_DATA_TYPE); + return ERROR_DIFF_DATA_TYPE; + } + + logError(0, "%s Type = %02X of Compensation data OK! \n", tag, type); + + header->type = type; + + *address = offset + COMP_DATA_HEADER; + + return OK; + +} + +/** +* Read MS Global Initialization data from the buffer such as Cx1 +* @param address pointer to a variable which contain the address from where to read the data and will contain the updated address to the next data +* @param global pointer to MutualSenseData variable which will contain the MS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readMutualSenseGlobalData(u64 *address, MutualSenseData *global) +{ + + u8 data[COMP_DATA_GLOBAL]; + int ret; + + logError(0, "%s Address for Global data= %04X \n", tag, *address); + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data, + COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, "%s %s: error while reading info data ERROR %08X\n", + tag, __func__, ret); + return ret; + } + logError(0, "%s Global data Read !\n", tag); + + global->header.force_node = data[0]; + global->header.sense_node = data[1]; + global->cx1 = data[2]; + + logError(0, "%s force_len = %d sense_len = %d CX1 = %d \n", tag, + global->header.force_node, global->header.sense_node, + global->cx1); + + *address += COMP_DATA_GLOBAL; + return OK; + +} + +/** +* Read MS Initialization data for each node from the buffer +* @param address a variable which contain the address from where to read the data +* @param node pointer to MutualSenseData variable which will contain the MS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readMutualSenseNodeData(u64 address, MutualSenseData *node) +{ + + int ret; + int size = node->header.force_node * node->header.sense_node; + + logError(0, "%s Address for Node data = %04X \n", tag, address); + + node->node_data = (i8 *) kmalloc(size * (sizeof(i8)), GFP_KERNEL); + + if (node->node_data == NULL) { + logError(1, "%s %s: can not allocate node_data... ERROR %08X", + tag, __func__, ERROR_ALLOC); + return ERROR_ALLOC; + } + + logError(0, "%s Node Data to read %d bytes \n", tag, size); + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, + node->node_data, size, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, + "%s %s: error while reading node data ERROR %08X \n", + tag, __func__, ret); + kfree(node->node_data); + node->node_data = NULL; + return ret; + } + node->node_data_size = size; + + logError(0, "%s Read node data OK! \n", tag); + + return size; + +} + +/** +* Perform all the steps to read the necessary info for MS Initialization data from the buffer and store it in a MutualSenseData variable +* @param type type of MS Initialization data to read @link load_opt Load Host Data Option @endlink +* @param data pointer to MutualSenseData variable which will contain the MS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readMutualSenseCompensationData(u8 type, MutualSenseData *data) +{ + + int ret; + u64 address; + data->node_data = NULL; + + if (! + (type == LOAD_CX_MS_TOUCH || type == LOAD_CX_MS_LOW_POWER + || type == LOAD_CX_MS_KEY || type == LOAD_CX_MS_FORCE)) { + logError(1, + "%s %s: Choose a MS type of compensation data ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + ret = requestCompensationData(type); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_REQU_COMP_DATA); + return (ret | ERROR_REQU_COMP_DATA); + } + + ret = readCompensationDataHeader(type, &(data->header), &address); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_HEADER); + return (ret | ERROR_COMP_DATA_HEADER); + } + + ret = readMutualSenseGlobalData(&address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X \n", tag, __func__, + ERROR_COMP_DATA_GLOBAL); + return (ret | ERROR_COMP_DATA_GLOBAL); + } + + ret = readMutualSenseNodeData(address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_NODE); + return (ret | ERROR_COMP_DATA_NODE); + } + + return OK; + +} + +/** +* Read SS Global Initialization data from the buffer such as Ix1/Cx1 for force and sense +* @param address pointer to a variable which contain the address from where to read the data and will contain the updated address to the next data +* @param global pointer to MutualSenseData variable which will contain the SS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readSelfSenseGlobalData(u64 *address, SelfSenseData *global) +{ + int ret; + u8 data[COMP_DATA_GLOBAL]; + + logError(0, "%s Address for Global data= %04X \n", tag, *address); + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data, + COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, + "%s %s: error while reading the data... ERROR %08X \n", + tag, __func__, ret); + return ret; + } + + logError(0, "%s Global data Read !\n", tag); + + global->header.force_node = data[0]; + global->header.sense_node = data[1]; + global->f_ix1 = data[2]; + global->s_ix1 = data[3]; + global->f_cx1 = (i8) data[4]; + global->s_cx1 = (i8) data[5]; + global->f_max_n = data[6]; + global->s_max_n = data[7]; + + logError(0, + "%s force_len = %d sense_len = %d f_ix1 = %d s_ix1 = %d f_cx1 = %d s_cx1 = %d \n", + tag, global->header.force_node, global->header.sense_node, + global->f_ix1, global->s_ix1, global->f_cx1, global->s_cx1); + logError(0, "%s max_n = %d s_max_n = %d \n", tag, global->f_max_n, + global->s_max_n); + + *address += COMP_DATA_GLOBAL; + + return OK; + +} + +/** +* Read SS Initialization data for each node of force and sense channels from the buffer +* @param address a variable which contain the address from where to read the data +* @param node pointer to SelfSenseData variable which will contain the SS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readSelfSenseNodeData(u64 address, SelfSenseData *node) +{ + + int size = node->header.force_node * 2 + node->header.sense_node * 2; + u8 data[size]; + int ret; + + node->ix2_fm = + (u8 *) kmalloc(node->header.force_node * (sizeof(u8)), GFP_KERNEL); + if (node->ix2_fm == NULL) { + logError(1, + "%s %s: can not allocate memory for ix2_fm... ERROR %08X", + tag, __func__, ERROR_ALLOC); + return ERROR_ALLOC; + } + + node->cx2_fm = + (i8 *) kmalloc(node->header.force_node * (sizeof(i8)), GFP_KERNEL); + if (node->cx2_fm == NULL) { + logError(1, + "%s %s: can not allocate memory for cx2_fm ... ERROR %08X", + tag, __func__, ERROR_ALLOC); + kfree(node->ix2_fm); + return ERROR_ALLOC; + } + node->ix2_sn = + (u8 *) kmalloc(node->header.sense_node * (sizeof(u8)), GFP_KERNEL); + if (node->ix2_sn == NULL) { + logError(1, + "%s %s: can not allocate memory for ix2_sn ERROR %08X", + tag, __func__, ERROR_ALLOC); + kfree(node->ix2_fm); + kfree(node->cx2_fm); + return ERROR_ALLOC; + } + node->cx2_sn = + (i8 *) kmalloc(node->header.sense_node * (sizeof(i8)), GFP_KERNEL); + if (node->cx2_sn == NULL) { + logError(1, + "%s %s: can not allocate memory for cx2_sn ERROR %08X", + tag, __func__, ERROR_ALLOC); + kfree(node->ix2_fm); + kfree(node->cx2_fm); + kfree(node->ix2_sn); + return ERROR_ALLOC; + } + + logError(0, "%s Address for Node data = %02X \n", tag, address); + + logError(0, "%s Node Data to read %d bytes \n", tag, size); + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data, + size, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, "%s %s: error while reading data... ERROR %08X\n", + tag, ret); + kfree(node->ix2_fm); + kfree(node->cx2_fm); + kfree(node->ix2_sn); + kfree(node->cx2_sn); + return ret; + } + + logError(0, "%s Read node data ok! \n", tag); + + memcpy(node->ix2_fm, data, node->header.force_node); + memcpy(node->ix2_sn, &data[node->header.force_node], + node->header.sense_node); + memcpy(node->cx2_fm, + &data[node->header.force_node + node->header.sense_node], + node->header.force_node); + memcpy(node->cx2_sn, + &data[node->header.force_node * 2 + node->header.sense_node], + node->header.sense_node); + + return OK; + +} + +/** +* Perform all the steps to read the necessary info for SS Initialization data from the buffer and store it in a SelfSenseData variable +* @param type type of SS Initialization data to read @link load_opt Load Host Data Option @endlink +* @param data pointer to SelfSenseData variable which will contain the SS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readSelfSenseCompensationData(u8 type, SelfSenseData *data) +{ + + int ret; + u64 address; + + data->ix2_fm = NULL; + data->cx2_fm = NULL; + data->ix2_sn = NULL; + data->cx2_sn = NULL; + + if (! + (type == LOAD_CX_SS_TOUCH || type == LOAD_CX_SS_TOUCH_IDLE + || type == LOAD_CX_SS_KEY || type == LOAD_CX_SS_FORCE)) { + logError(1, + "%s %s: Choose a SS type of compensation data ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + ret = requestCompensationData(type); + if (ret < 0) { + logError(1, + "%s %s: error while requesting data... ERROR %08X\n", + tag, __func__, ERROR_REQU_COMP_DATA); + return (ret | ERROR_REQU_COMP_DATA); + } + + ret = readCompensationDataHeader(type, &(data->header), &address); + if (ret < 0) { + logError(1, + "%s %s: error while reading data header... ERROR %08X\n", + tag, __func__, ERROR_COMP_DATA_HEADER); + return (ret | ERROR_COMP_DATA_HEADER); + } + + ret = readSelfSenseGlobalData(&address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_GLOBAL); + return (ret | ERROR_COMP_DATA_GLOBAL); + } + + ret = readSelfSenseNodeData(address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_NODE); + return (ret | ERROR_COMP_DATA_NODE); + } + + return OK; + +} + +/** +* Read TOT MS Global Initialization data from the buffer such as number of force and sense channels +* @param address pointer to a variable which contain the address from where to read the data and will contain the updated address to the next data +* @param global pointer to a variable which will contain the TOT MS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readTotMutualSenseGlobalData(u64 *address, TotMutualSenseData *global) +{ + int ret; + u8 data[COMP_DATA_GLOBAL]; + + logError(0, "%s Address for Global data= %04X \n", tag, *address); + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data, + COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, "%s %s: error while reading info data ERROR %08X\n", + tag, __func__, ret); + return ret; + } + logError(0, "%s Global data Read !\n", tag); + + global->header.force_node = data[0]; + global->header.sense_node = data[1]; + + logError(0, "%s force_len = %d sense_len = %d \n", tag, + global->header.force_node, global->header.sense_node); + + *address += COMP_DATA_GLOBAL; + return OK; + +} + +/** +* Read TOT MS Initialization data for each node from the buffer +* @param address a variable which contain the address from where to read the data +* @param node pointer to MutualSenseData variable which will contain the TOT MS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readTotMutualSenseNodeData(u64 address, TotMutualSenseData *node) +{ + int ret, i; + int size = node->header.force_node * node->header.sense_node; + int toRead = size * sizeof(u16); + u8 data[toRead]; + + logError(0, "%s Address for Node data = %04X \n", tag, address); + + node->node_data = (short *)kmalloc(size * (sizeof(short)), GFP_KERNEL); + + if (node->node_data == NULL) { + logError(1, "%s %s: can not allocate node_data... ERROR %08X", + tag, __func__, ERROR_ALLOC); + return ERROR_ALLOC; + } + + logError(0, "%s Node Data to read %d bytes \n", tag, size); + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data, + toRead, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, + "%s %s: error while reading node data ERROR %08X \n", + tag, __func__, ret); + kfree(node->node_data); + node->node_data = NULL; + return ret; + } + node->node_data_size = size; + + for (i = 0; i < size; i++) { + node->node_data[i] = + ((short)data[i * 2 + 1]) << 8 | data[i * 2]; + } + + logError(0, "%s Read node data OK! \n", tag); + + return size; + +} + +/** +* Perform all the steps to read the necessary info for TOT MS Initialization data from the buffer and store it in a TotMutualSenseData variable +* @param type type of TOT MS Initialization data to read @link load_opt Load Host Data Option @endlink +* @param data pointer to a variable which will contain the TOT MS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readTotMutualSenseCompensationData(u8 type, TotMutualSenseData *data) +{ + int ret; + u64 address; + data->node_data = NULL; + + if (! + (type == LOAD_PANEL_CX_TOT_MS_TOUCH + || type == LOAD_PANEL_CX_TOT_MS_LOW_POWER + || type == LOAD_PANEL_CX_TOT_MS_KEY + || type == LOAD_PANEL_CX_TOT_MS_FORCE)) { + logError(1, + "%s %s: Choose a TOT MS type of compensation data ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + ret = requestCompensationData(type); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_REQU_COMP_DATA); + return (ret | ERROR_REQU_COMP_DATA); + } + + ret = readCompensationDataHeader(type, &(data->header), &address); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_HEADER); + return (ret | ERROR_COMP_DATA_HEADER); + } + + ret = readTotMutualSenseGlobalData(&address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X \n", tag, __func__, + ERROR_COMP_DATA_GLOBAL); + return (ret | ERROR_COMP_DATA_GLOBAL); + } + + ret = readTotMutualSenseNodeData(address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_NODE); + return (ret | ERROR_COMP_DATA_NODE); + } + + return OK; + +} + +/** +* Read TOT SS Global Initialization data from the buffer such as number of force and sense channels +* @param address pointer to a variable which contain the address from where to read the data and will contain the updated address to the next data +* @param global pointer to a variable which will contain the TOT SS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readTotSelfSenseGlobalData(u64 *address, TotSelfSenseData *global) +{ + int ret; + u8 data[COMP_DATA_GLOBAL]; + + logError(0, "%s Address for Global data= %04X \n", tag, *address); + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, *address, data, + COMP_DATA_GLOBAL, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, + "%s %s: error while reading the data... ERROR %08X \n", + tag, __func__, ret); + return ret; + } + + logError(0, "%s Global data Read !\n", tag); + + global->header.force_node = data[0]; + global->header.sense_node = data[1]; + + logError(0, "%s force_len = %d sense_len = %d \n", tag, + global->header.force_node, global->header.sense_node); + + *address += COMP_DATA_GLOBAL; + + return OK; + +} + +/** +* Read TOT SS Global Initialization data from the buffer such as number of force and sense channels +* @param address pointer to a variable which contain the address from where to read the data and will contain the updated address to the next data +* @param node pointer to a variable which will contain the TOT SS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readTotSelfSenseNodeData(u64 address, TotSelfSenseData *node) +{ + + int size = node->header.force_node * 2 + node->header.sense_node * 2; + int toRead = size * 2; + u8 data[toRead]; + int ret, i, j = 0; + + node->ix_fm = + (u16 *) kmalloc(node->header.force_node * (sizeof(u16)), + GFP_KERNEL); + if (node->ix_fm == NULL) { + logError(1, + "%s %s: can not allocate memory for ix2_fm... ERROR %08X", + tag, __func__, ERROR_ALLOC); + return ERROR_ALLOC; + } + + node->cx_fm = + (short *)kmalloc(node->header.force_node * (sizeof(short)), + GFP_KERNEL); + if (node->cx_fm == NULL) { + logError(1, + "%s %s: can not allocate memory for cx2_fm ... ERROR %08X", + tag, __func__, ERROR_ALLOC); + kfree(node->ix_fm); + return ERROR_ALLOC; + } + node->ix_sn = + (u16 *) kmalloc(node->header.sense_node * (sizeof(u16)), + GFP_KERNEL); + if (node->ix_sn == NULL) { + logError(1, + "%s %s: can not allocate memory for ix2_sn ERROR %08X", + tag, __func__, ERROR_ALLOC); + kfree(node->ix_fm); + kfree(node->cx_fm); + return ERROR_ALLOC; + } + node->cx_sn = + (short *)kmalloc(node->header.sense_node * (sizeof(short)), + GFP_KERNEL); + if (node->cx_sn == NULL) { + logError(1, + "%s %s: can not allocate memory for cx2_sn ERROR %08X", + tag, __func__, ERROR_ALLOC); + kfree(node->ix_fm); + kfree(node->cx_fm); + kfree(node->ix_sn); + return ERROR_ALLOC; + } + + logError(0, "%s Address for Node data = %02X \n", tag, address); + + logError(0, "%s Node Data to read %d bytes \n", tag, size); + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data, + toRead, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, "%s %s: error while reading data... ERROR %08X\n", + tag, ret); + kfree(node->ix_fm); + kfree(node->cx_fm); + kfree(node->ix_sn); + kfree(node->cx_sn); + return ret; + } + + logError(0, "%s Read node data ok! \n", tag); + + j = 0; + for (i = 0; i < node->header.force_node; i++) { + node->ix_fm[i] = ((u16) data[j + 1]) << 8 | data[j]; + j += 2; + } + + for (i = 0; i < node->header.sense_node; i++) { + node->ix_sn[i] = ((u16) data[j + 1]) << 8 | data[j]; + j += 2; + } + + for (i = 0; i < node->header.force_node; i++) { + node->cx_fm[i] = ((short)data[j + 1]) << 8 | data[j]; + j += 2; + } + + for (i = 0; i < node->header.sense_node; i++) { + node->cx_sn[i] = ((short)data[j + 1]) << 8 | data[j]; + j += 2; + } + + if (j != toRead) { + logError(1, "%s %s: parsed a wrong number of bytes %d!=%d \n", + tag, __func__, j, toRead); + } + + return OK; + +} + +/** +* Perform all the steps to read the necessary info for TOT SS Initialization data from the buffer and store it in a TotSelfSenseData variable +* @param type type of TOT MS Initialization data to read @link load_opt Load Host Data Option @endlink +* @param data pointer to a variable which will contain the TOT MS initialization data +* @return OK if success or an error code which specify the type of error encountered +*/ +int readTotSelfSenseCompensationData(u8 type, TotSelfSenseData *data) +{ + + int ret; + u64 address; + + data->ix_fm = NULL; + data->cx_fm = NULL; + data->ix_sn = NULL; + data->cx_sn = NULL; + + if (! + (type == LOAD_PANEL_CX_TOT_SS_TOUCH + || type == LOAD_PANEL_CX_TOT_SS_TOUCH_IDLE + || type == LOAD_PANEL_CX_TOT_SS_KEY + || type == LOAD_PANEL_CX_TOT_SS_FORCE + || type == STAPI_HOST_DATA_ID_PANEL_CX_SS_HVR)) { + logError(1, + "%s %s: Choose a TOT SS type of compensation data ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + ret = requestCompensationData(type); + if (ret < 0) { + logError(1, + "%s %s: error while requesting data... ERROR %08X\n", + tag, __func__, ERROR_REQU_COMP_DATA); + return (ret | ERROR_REQU_COMP_DATA); + } + + ret = readCompensationDataHeader(type, &(data->header), &address); + if (ret < 0) { + logError(1, + "%s %s: error while reading data header... ERROR %08X\n", + tag, __func__, ERROR_COMP_DATA_HEADER); + return (ret | ERROR_COMP_DATA_HEADER); + } + + ret = readTotSelfSenseGlobalData(&address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_GLOBAL); + return (ret | ERROR_COMP_DATA_GLOBAL); + } + + ret = readTotSelfSenseNodeData(address, data); + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_COMP_DATA_NODE); + return (ret | ERROR_COMP_DATA_NODE); + } + + return OK; + +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsCompensation.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsCompensation.h new file mode 100644 index 000000000000..1917e7484142 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsCompensation.h @@ -0,0 +1,110 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS functions for getting Initialization Data * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsCompensation.h +* \brief Contains all the definitions and structs to work with Initialization Data +*/ + +#ifndef FTS_COMPENSATION_H +#define FTS_COMPENSATION_H + +#include "ftsCore.h" +#include "ftsSoftware.h" + +#define RETRY_COMP_DATA_READ 2 + +/*Bytes dimension of Compensation Data Format*/ + +#define COMP_DATA_HEADER DATA_HEADER +#define COMP_DATA_GLOBAL (16 - COMP_DATA_HEADER) + +#define HEADER_SIGNATURE 0xA5 + +/** +* Struct which contains the general info about Frames and Initialization Data +*/ +typedef struct { + int force_node; /*Number of Force Channels in the frame/Initialization data*/ + int sense_node; /*Number of Sense Channels in the frame/Initialization data*/ + int type; /*Type of frame/Initialization data*/ +} DataHeader; + +/** +* Struct which contains the MS Initialization data +*/ +typedef struct { + DataHeader header; /*Header*/ + i8 cx1; /*Cx1 value (can be negative))*/ + i8 *node_data; /*Pointer to an array of bytes which contains the CX2 data (can be negative)*/ + int node_data_size; /*size of the data*/ +} MutualSenseData; + +/** +* Struct which contains the SS Initialization data +*/ +typedef struct { + DataHeader header; /*Header*/ + u8 f_ix1; /*IX1 Force*/ + u8 s_ix1; /*IX1 Sense*/ + i8 f_cx1; /*CX1 Force (can be negative)*/ + i8 s_cx1; /*< CX1 Sense (can be negative)*/ + u8 f_max_n; /*Force MaxN*/ + u8 s_max_n; /*Sense MaxN*/ + + u8 *ix2_fm; /*pointer to an array of bytes which contains Force Ix2 data node*/ + u8 *ix2_sn; /*pointer to an array of bytes which contains Sense Ix2 data node*/ + i8 *cx2_fm; /*pointer to an array of bytes which contains Force Cx2 data node (can be negative)*/ + i8 *cx2_sn; /*pointer to an array of bytes which contains Sense Cx2 data node (can be negative))*/ + +} SelfSenseData; + +/** +* Struct which contains the TOT MS Initialization data +*/ +typedef struct { + DataHeader header; /*Header*/ + short *node_data; /*pointer to an array of ushort which contains TOT MS Initialization data*/ + int node_data_size; /*size of data*/ +} TotMutualSenseData; + +/** +* Struct which contains the TOT SS Initialization data +*/ +typedef struct { + DataHeader header; /*Header*/ + + u16 *ix_fm; /*pointer to an array of ushort which contains TOT SS IX Force data*/ + u16 *ix_sn; /*pointer to an array of ushort which contains TOT SS IX Sense data*/ + short *cx_fm; /*pointer to an array of ushort which contains TOT SS CX Force data (can be negative)*/ + short *cx_sn; /*pointer to an array of ushort which contains TOT SS CX Sense data (can be negative)*/ + +} TotSelfSenseData; + +int requestCompensationData(u8 type); +int readCompensationDataHeader(u8 type, DataHeader *header, u64 *address); +int readMutualSenseGlobalData(u64 *address, MutualSenseData *global); +int readMutualSenseNodeData(u64 address, MutualSenseData *node); +int readMutualSenseCompensationData(u8 type, MutualSenseData *data); +int readSelfSenseGlobalData(u64 *address, SelfSenseData *global); +int readSelfSenseNodeData(u64 address, SelfSenseData *node); +int readSelfSenseCompensationData(u8 type, SelfSenseData *data); +int readToTMutualSenseGlobalData(u64 *address, TotMutualSenseData *global); +int readToTMutualSenseNodeData(u64 address, TotMutualSenseData *node); +int readTotMutualSenseCompensationData(u8 type, TotMutualSenseData *data); +int readTotSelfSenseGlobalData(u64 *address, TotSelfSenseData *global); +int readTotSelfSenseNodeData(u64 address, TotSelfSenseData *node); +int readTotSelfSenseCompensationData(u8 type, TotSelfSenseData *data); +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsCore.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsCore.c new file mode 100644 index 000000000000..f1a4806f55aa --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsCore.c @@ -0,0 +1,1365 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS Core functions * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsCore.c +* \brief Contains the implementation of the Core functions +*/ + +#include +#include +#include +#include +#include +#include "ftsCompensation.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsIO.h" +#include "ftsTest.h" +#include "ftsTime.h" +#include "ftsTool.h" + +extern struct fts_ts_info *fts_info; +/** @addtogroup system_info +* @{ +*/ +SysInfo systemInfo; /*Global System Info variable, accessible in all the driver*/ +/** @}*/ + +static int reset_gpio = GPIO_NOT_DEFINED; /*gpio number of the rest pin, the value is GPIO_NOT_DEFINED if the reset pin is not connected*/ +static int system_reseted_up; /*flag checked during resume to understand if there was a system reset and restore the proper state*/ +static int system_reseted_down; /*flag checked during suspend to understand if there was a system reset and restore the proper state*/ +static int disable_irq_count; /*count the number of call to disable_irq, start with 1 because at the boot IRQ are already disabled*/ +spinlock_t fts_int; /*spinlock to controll the access to the disable_irq_counter*/ + +/** +* Initialize core variables of the library. Must be called during the probe before any other lib function +* @param info pointer to fts_ts_info which contains info about the device and its hw setup +* @return OK if success or an error code which specify the type of error encountered +*/ +int initCore(struct fts_ts_info *info) +{ + int ret = OK; + logError(0, "%s %s: Initialization of the Core... \n", tag, __func__); + ret |= openChannel(info->client); + ret |= resetErrorList(); + ret |= initTestToDo(); + setResetGpio(info->board->reset_gpio); + if (ret < OK) { + logError(0, "%s %s: Initialization Core ERROR %08X! \n", tag, + __func__, ret); + } else { + logError(0, "%s %s: Initialization Finished! \n", tag, + __func__); + } + return ret; +} + +/** +* Set the reset_gpio variable with the actual gpio number of the board link to the reset pin +* @param gpio gpio number link to the reset pin of the IC +*/ +void setResetGpio(int gpio) +{ + reset_gpio = gpio; + logError(0, "%s setResetGpio: reset_gpio = %d\n", tag, reset_gpio); +} + +/** +* Perform a system reset of the IC. +* If the reset pin is associated to a gpio, the function execute an hw reset (toggling of reset pin) otherwise send an hw command to the IC +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_system_reset(void) +{ + u8 readData[FIFO_EVENT_SIZE]; + int event_to_search; + int res = -1; + int i; + u8 data[1] = { SYSTEM_RESET_VALUE }; + event_to_search = (int)EVT_ID_CONTROLLER_READY; + + logError(1, "%s System resetting...\n", tag); + if (fts_info) { + reinit_completion(&fts_info->tp_reset_completion); + atomic_set(&fts_info->system_is_resetting, 1); + } + for (i = 0; i < RETRY_SYSTEM_RESET && res < 0; i++) { + resetErrorList(); + fts_disableInterruptNoSync(); + + if (reset_gpio == GPIO_NOT_DEFINED) { + res = + fts_writeU8UX(FTS_CMD_HW_REG_W, ADDR_SIZE_HW_REG, + ADDR_SYSTEM_RESET, data, + ARRAY_SIZE(data)); + } else { + gpio_set_value(reset_gpio, 0); + mdelay(10); + gpio_set_value(reset_gpio, 1); + res = OK; + } + if (res < OK) { + logError(1, "%s fts_system_reset: ERROR %08X\n", tag, + ERROR_BUS_W); + } else { + res = + pollForEvent(&event_to_search, 1, readData, + GENERAL_TIMEOUT); + if (res < OK) { + logError(1, "%s fts_system_reset: ERROR %08X\n", + tag, res); + } + } + } + if (fts_info) { + complete(&fts_info->tp_reset_completion); + atomic_set(&fts_info->system_is_resetting, 0); + } + if (res < OK) { + logError(1, + "%s fts_system_reset...failed after 3 attempts: ERROR %08X\n", + tag, (res | ERROR_SYSTEM_RESET_FAIL)); + return (res | ERROR_SYSTEM_RESET_FAIL); + } else { + logError(1, "%s System reset DONE!\n", tag); + system_reseted_down = 1; + system_reseted_up = 1; + return OK; + } + +} + +/** +* Return the value of system_resetted_down. +* @return the flag value: 0 if not set, 1 if set +*/ +int isSystemResettedDown(void) +{ + return system_reseted_down; +} + +/** +* Return the value of system_resetted_up. +* @return the flag value: 0 if not set, 1 if set +*/ +int isSystemResettedUp(void) +{ + return system_reseted_up; +} + +/** +* Set the value of system_reseted_down flag +* @param val value to write in the flag +*/ +void setSystemResetedDown(int val) +{ + system_reseted_down = val; +} + +/** +* Set the value of system_reseted_up flag +* @param val value to write in the flag +*/ +void setSystemResetedUp(int val) +{ + system_reseted_up = val; +} + +/** @addtogroup events_group + * @{ + */ + +/** +* Poll the FIFO looking for a specified event within a timeout. Support a retry mechanism. +* @param event_to_search pointer to an array of int where each element correspond to a byte of the event to find. If the element of the array has value -1, the byte of the event, in the same position of the element is ignored. +* @param event_bytes size of event_to_search +* @param readData pointer to an array of byte which will contain the event found +* @param time_to_wait time to wait before going in timeout +* @return OK if success or an error code which specify the type of error encountered +*/ +int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, + int time_to_wait) +{ + int i, find, retry, count_err; + int time_to_count; + int err_handling = OK; + StopWatch clock; + + u8 cmd[1] = { FIFO_CMD_READONE }; + char temp[128] = { 0 }; + + find = 0; + retry = 0; + count_err = 0; + time_to_count = time_to_wait / TIMEOUT_RESOLUTION; + + startStopWatch(&clock); + while (find != 1 && retry < time_to_count + && fts_writeReadU8UX(cmd[0], 0, 0, readData, FIFO_EVENT_SIZE, + DUMMY_FIFO) >= OK) { + + if (readData[0] == EVT_ID_ERROR) { + + logError(1, "%s %s\n", tag, + printHex("ERROR EVENT = ", readData, + FIFO_EVENT_SIZE, temp)); + memset(temp, 0, 128); + count_err++; + err_handling = errorHandler(readData, FIFO_EVENT_SIZE); + if ((err_handling & 0xF0FF0000) == + ERROR_HANDLER_STOP_PROC) { + logError(0, + "%s pollForEvent: forced to be stopped! ERROR %08X\n", + tag, err_handling); + return err_handling; + } + } else { + if (readData[0] != EVT_ID_NOEVENT) { + logError(0, "%s %s\n", tag, + printHex("READ EVENT = ", readData, + FIFO_EVENT_SIZE, temp)); + memset(temp, 0, 128); + + } + if (readData[0] == EVT_ID_CONTROLLER_READY + && event_to_search[0] != EVT_ID_CONTROLLER_READY) { + logError(0, + "%s pollForEvent: Unmanned Controller Ready Event! Setting reset flags...\n", + tag); + setSystemResetedUp(1); + setSystemResetedDown(1); + } + } + + find = 1; + + for (i = 0; i < event_bytes; i++) { + + if (event_to_search[i] != -1 + && (int)readData[i] != event_to_search[i]) { + find = 0; + break; + } + } + + retry++; + mdelay(TIMEOUT_RESOLUTION); + } + stopStopWatch(&clock); + if ((retry >= time_to_count) && find != 1) { + logError(1, "%s pollForEvent: ERROR %02X \n", tag, + ERROR_TIMEOUT); + return ERROR_TIMEOUT; + } else if (find == 1) { + logError(0, "%s %s\n", tag, + printHex("FOUND EVENT = ", readData, FIFO_EVENT_SIZE, + temp)); + memset(temp, 0, 128); + logError(0, + "%s Event found in %d ms (%d iterations)! Number of errors found = %d \n", + tag, elapsedMillisecond(&clock), retry, count_err); + return count_err; + } else { + logError(1, "%s pollForEvent: ERROR %08X \n", tag, ERROR_BUS_R); + return ERROR_BUS_R; + } +} + +/** @}*/ + +/** +* Check that the FW sent the echo even after a command was sent +* @param cmd pointer to an array of byte which contain the command previously sent +* @param size size of cmd +* @return OK if success or an error code which specify the type of error encountered +*/ +int checkEcho(u8 *cmd, int size) +{ + int ret, i; + int event_to_search[FIFO_EVENT_SIZE]; + u8 readData[FIFO_EVENT_SIZE]; + + if (size < 1) { + logError(1, "%s checkEcho: Error Size = %d not valid! \n", tag, + size, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } else { + if ((size + 3) > FIFO_EVENT_SIZE) + size = FIFO_EVENT_SIZE - 3; + + event_to_search[0] = EVT_ID_STATUS_UPDATE; + event_to_search[1] = EVT_TYPE_STATUS_ECHO; + for (i = 2; i < size + 2; i++) { + event_to_search[i] = cmd[i - 2]; + } + ret = + pollForEvent(event_to_search, size + 2, readData, + TIMEOUT_ECHO); + if (ret < OK) { + logError(1, + "%s checkEcho: Echo Event not found! ERROR %08X\n", + tag, ret); + return (ret | ERROR_CHECK_ECHO_FAIL); + } else if (ret > OK) { + logError(1, + "%s checkEcho: Echo Event found but with some error events before! num_error = %d \n", + tag, ret); + return ERROR_CHECK_ECHO_FAIL; + } + + logError(0, "%s ECHO OK!\n", tag); + return ret; + } + +} + +/** @addtogroup scan_mode +* @{ +*/ +/** +* Set a scan mode in the IC +* @param mode scan mode to set; possible values @link scan_opt Scan Mode Option @endlink +* @param settings option for the selected scan mode (for example @link active_bitmask Active Mode Bitmask @endlink) +* @return OK if success or an error code which specify the type of error encountered +*/ +int setScanMode(u8 mode, u8 settings) +{ + u8 cmd[3] = { FTS_CMD_SCAN_MODE, mode, settings }; + int ret, size = 3; + + logError(0, "%s %s: Setting scan mode: mode = %02X settings = %02X !\n", + tag, __func__, mode, settings); + if (mode == SCAN_MODE_LOW_POWER) + size = 2; + ret = fts_write_dma_safe(cmd, size); + if (ret < OK) { + logError(1, "%s %s: write failed...ERROR %08X !\n", tag, + __func__, ret); + return ret | ERROR_SET_SCAN_MODE_FAIL; + } + logError(0, "%s %s: Setting scan mode OK!\n", tag, __func__); + return OK; +} + +/** @}*/ + +/** @addtogroup feat_sel +* @{ +*/ +/** +* Set a feature and its option in the IC +* @param feat feature to set; possible values @link feat_opt Feature Selection Option @endlink +* @param settings pointer to an array of byte which store the options for the selected feature (for example the gesture mask to activate @link gesture_opt Gesture IDs @endlink) +* @param size in bytes of settings +* @return OK if success or an error code which specify the type of error encountered +*/ +int setFeatures(u8 feat, u8 *settings, int size) +{ + u8 cmd[2 + size]; + int i = 0; + int ret; + logError(0, "%s %s: Setting feature: feat = %02X !\n", tag, __func__, + feat); + cmd[0] = FTS_CMD_FEATURE; + cmd[1] = feat; + logError(0, "%s %s: Settings = ", tag, __func__); + for (i = 0; i < size; i++) { + cmd[2 + i] = settings[i]; + logError(0, "%02X ", settings[i]); + } + logError(0, "\n"); + ret = fts_write_dma_safe(cmd, 2 + size); + if (ret < OK) { + logError(1, "%s %s: write failed...ERROR %08X !\n", tag, + __func__, ret); + return ret | ERROR_SET_FEATURE_FAIL; + } + logError(0, "%s %s: Setting feature OK!\n", tag, __func__); + return OK; +} + +/** @}*/ + +/** @addtogroup sys_cmd +* @{ +*/ +/** +* Write a system command to the IC +* @param sys_cmd System Command to execute; possible values @link sys_opt System Command Option @endlink +* @param sett settings option for the selected system command (@link sys_special_opt Special Command Option @endlink, @link ito_opt ITO Test Option @endlink, @link load_opt Load Host Data Option @endlink) +* @param size in bytes of settings +* @return OK if success or an error code which specify the type of error encountered +*/ +int writeSysCmd(u8 sys_cmd, u8 *sett, int size) +{ + u8 *cmd = NULL; + int ret; + + cmd = (u8 *)kzalloc(sizeof(u8) * size + 2, GFP_KERNEL); + if (!cmd) { + ret = ERROR_ALLOC; + goto end; + } + + cmd[0] = FTS_CMD_SYSTEM; + cmd[1] = sys_cmd; + + logError(0, "%s %s: Command = %02X %02X ", tag, __func__, cmd[0], + cmd[1]); + for (ret = 0; ret < size; ret++) { + cmd[2 + ret] = sett[ret]; + logError(0, "%02X ", cmd[2 + ret]); + } + logError(0, "\n%s %s: Writing Sys command...\n", tag, __func__); + if (sys_cmd != SYS_CMD_LOAD_DATA) { + ret = fts_writeFwCmd(cmd, 2 + size); + } else { + if (size >= 1) { + ret = requestSyncFrame(sett[0]); + } else { + logError(1, "%s %s: No setting argument! ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + ret = ERROR_OP_NOT_ALLOW; + goto end; + } + } + if (ret < OK) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ret); + } else + logError(0, "%s %s: FINISHED! \n", tag, __func__); + +end: + if (cmd) + kfree(cmd); + return ret; +} + +/** @}*/ + +/** @addtogroup system_info +* @{ +*/ +/** +* Initialize the System Info Struct with default values according to the error found during the reading +* @param i2cError 1 if there was an I2C error while reading the System Info data from memory, other value if another error occurred +* @return OK if success or an error code which specify the type of error encountered +*/ +int defaultSysInfo(int i2cError) +{ + int i; + logError(0, "%s Setting default System Info... \n", tag); + + if (i2cError == 1) { + systemInfo.u16_fwVer = 0xFFFF; + systemInfo.u16_cfgProgectId = 0xFFFF; + for (i = 0; i < RELEASE_INFO_SIZE; i++) { + systemInfo.u8_releaseInfo[i] = 0xFF; + } + systemInfo.u16_cxVer = 0xFFFF; + } else { + systemInfo.u16_fwVer = 0x0000; + systemInfo.u16_cfgProgectId = 0x0000; + for (i = 0; i < RELEASE_INFO_SIZE; i++) { + systemInfo.u8_releaseInfo[i] = 0x00; + } + systemInfo.u16_cxVer = 0x0000; + } + + systemInfo.u8_scrRxLen = 0; + systemInfo.u8_scrTxLen = 0; + + logError(0, "%s default System Info DONE! \n", tag); + return OK; + +} + +/** +* Read the System Info data from memory. System Info is loaded automatically after every system reset. +* @param request if 1, will be asked to the FW to reload the data, otherwise attempt to read it directly from memory +* @return OK if success or an error code which specify the type of error encountered +*/ +int readSysInfo(int request) +{ + int ret, i, index = 0; + u8 sett = LOAD_SYS_INFO; + u8 data[SYS_INFO_SIZE] = { 0 }; + char temp[256] = { 0 }; + + if (request == 1) { + logError(0, "%s %s: Requesting System Info...\n", tag, + __func__); + + ret = writeSysCmd(SYS_CMD_LOAD_DATA, &sett, 1); + if (ret < OK) { + logError(1, + "%s %s: error while writing the sys cmd ERROR %08X\n", + tag, __func__, ret); + goto FAIL; + } + } + + logError(0, "%s %s: Reading System Info...\n", tag, __func__); + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, ADDR_FRAMEBUFFER, + data, SYS_INFO_SIZE, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, + "%s %s: error while reading the system data ERROR %08X\n", + tag, __func__, ret); + goto FAIL; + } + + logError(0, "%s %s: Parsing System Info...\n", tag, __func__); + + if (data[0] != HEADER_SIGNATURE) { + logError(1, + "%s %s: The Header Signature is wrong! sign: %02X != %02X ERROR %08X\n", + tag, __func__, data[0], HEADER_SIGNATURE, + ERROR_WRONG_DATA_SIGN); + ret = ERROR_WRONG_DATA_SIGN; + goto FAIL; + } + + if (data[1] != LOAD_SYS_INFO) { + logError(1, + "%s %s: The Data ID is wrong! ids: %02X != %02X ERROR %08X \n", + tag, __func__, data[3], LOAD_SYS_INFO, + ERROR_DIFF_DATA_TYPE); + ret = ERROR_DIFF_DATA_TYPE; + goto FAIL; + } + + index += 4; + u8ToU16(&data[index], &systemInfo.u16_apiVer_rev); + index += 2; + systemInfo.u8_apiVer_minor = data[index++]; + systemInfo.u8_apiVer_major = data[index++]; + u8ToU16(&data[index], &systemInfo.u16_chip0Ver); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_chip0Id); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_chip1Ver); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_chip1Id); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_fwVer); + index += 2; + logError(1, "%s FW VER = %04X \n", tag, systemInfo.u16_fwVer); + + u8ToU16(&data[index], &systemInfo.u16_svnRev); + index += 2; + logError(1, "%s SVN REV = %04X \n", tag, systemInfo.u16_svnRev); + u8ToU16(&data[index], &systemInfo.u16_cfgVer); + index += 2; + logError(1, "%s CONFIG VER = %04X \n", tag, systemInfo.u16_cfgVer); + u8ToU16(&data[index], &systemInfo.u16_cfgProgectId); + index += 2; + logError(1, "%s CONFIG PROJECT ID = %04X \n", tag, + systemInfo.u16_cfgProgectId); + u8ToU16(&data[index], &systemInfo.u16_cxVer); + index += 2; + logError(1, "%s CX VER = %04X \n", tag, systemInfo.u16_cxVer); + u8ToU16(&data[index], &systemInfo.u16_cxProjectId); + index += 2; + logError(1, "%s CX PROJECT ID = %04X \n", tag, + systemInfo.u16_cxProjectId); + systemInfo.u8_cfgAfeVer = data[index++]; + systemInfo.u8_cxAfeVer = data[index++]; + systemInfo.u8_panelCfgAfeVer = data[index++]; + logError(1, "%s AFE VER: CFG = %02X - CX = %02X - PANEL = %02X \n", tag, + systemInfo.u8_cfgAfeVer, systemInfo.u8_cxAfeVer, + systemInfo.u8_panelCfgAfeVer); + systemInfo.u8_protocol = data[index++]; + logError(0, "%s Protocol = %02X \n", tag, systemInfo.u8_protocol); + + for (i = 0; i < DIE_INFO_SIZE; i++) { + systemInfo.u8_dieInfo[i] = data[index++]; + + } + logError(0, "%s %s \n", tag, + printHex("Die Info = ", systemInfo.u8_dieInfo, DIE_INFO_SIZE, + temp)); + memset(temp, 0, 256); + + for (i = 0; i < RELEASE_INFO_SIZE; i++) { + systemInfo.u8_releaseInfo[i] = data[index++]; + } + + logError(1, "%s %s \n", tag, + printHex("Release Info = ", systemInfo.u8_releaseInfo, + RELEASE_INFO_SIZE, temp)); + memset(temp, 0, 256); + + u8ToU32(&data[index], &systemInfo.u32_fwCrc); + index += 4; + u8ToU32(&data[index], &systemInfo.u32_cfgCrc); + + index += 4; + + index += 8; + + u8ToU16(&data[index], &systemInfo.u16_scrResX); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_scrResY); + index += 2; + logError(0, "%s Screen Resolution = %d x %d \n", tag, + systemInfo.u16_scrResX, systemInfo.u16_scrResY); + systemInfo.u8_scrTxLen = data[index++]; + logError(0, "%s TX Len = %d \n", tag, systemInfo.u8_scrTxLen); + systemInfo.u8_scrRxLen = data[index++]; + logError(0, "%s RX Len = %d \n", tag, systemInfo.u8_scrRxLen); + systemInfo.u8_keyLen = data[index++]; + logError(0, "%s Key Len = %d \n", tag, systemInfo.u8_keyLen); + systemInfo.u8_forceLen = data[index++]; + logError(0, "%s Force Len = %d \n", tag, systemInfo.u8_forceLen); + + index += 40; + + u8ToU16(&data[index], &systemInfo.u16_dbgInfoAddr); + index += 2; + + index += 6; + + u8ToU16(&data[index], &systemInfo.u16_msTchRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_msTchFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_msTchStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_msTchBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_ssTchTxRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssTchTxFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssTchTxStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssTchTxBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_ssTchRxRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssTchRxFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssTchRxStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssTchRxBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_keyRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_keyFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_keyStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_keyBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_frcRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_frcFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_frcStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_frcBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_ssHvrTxRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssHvrTxFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssHvrTxStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssHvrTxBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_ssHvrRxRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssHvrRxFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssHvrRxStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssHvrRxBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_ssPrxTxRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssPrxTxFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssPrxTxStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssPrxTxBaselineAddr); + index += 2; + + u8ToU16(&data[index], &systemInfo.u16_ssPrxRxRawAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssPrxRxFilterAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssPrxRxStrenAddr); + index += 2; + u8ToU16(&data[index], &systemInfo.u16_ssPrxRxBaselineAddr); + index += 2; + + logError(0, "%s Parsed %d bytes! \n", tag, index); + + if (index != SYS_INFO_SIZE) { + logError(1, "%s %s: index = %d different from %d ERROR %08X\n", + tag, __func__, index, SYS_INFO_SIZE, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + logError(0, "%s System Info Read DONE!\n", tag); + return OK; + +FAIL: + defaultSysInfo(isI2cError(ret)); + return ret; + +} + +/** @}*/ + +/** + * Read data from the Config Memory + * @param offset Starting address in the Config Memory of data to read + * @param outBuf pointer of a byte array which contain the bytes to read + * @param len number of bytes to read + * @return OK if success or an error code which specify the type of error encountered + */ +int readConfig(u16 offset, u8 *outBuf, int len) +{ + int ret; + u64 final_address = offset + ADDR_CONFIG_OFFSET; + + logError(0, "%s %s: Starting to read config memory at %08X ...", tag, + __func__, final_address); + ret = + fts_writeReadU8UX(FTS_CMD_CONFIG_R, BITS_16, final_address, outBuf, + len, DUMMY_CONFIG); + if (ret < OK) { + logError(1, + "%s %s: Impossible to read Config Memory... ERROR %08X!", + tag, __func__, ret); + return ret; + } + + logError(0, "%s %s: Read config memory FINISHED!", tag, __func__); + return OK; +} + +/** + * Disable the interrupt so the ISR of the driver can not be called + * @return OK if success or an error code which specify the type of error encountered + */ +int fts_disableInterrupt(void) +{ + if (getClient() != NULL) { + logError(0, "%s Number of disable = %d \n", tag, + disable_irq_count); + if (disable_irq_count == 0) { + logError(0, "%s Excecuting Disable... \n", tag); + disable_irq(getClient()->irq); + disable_irq_count++; + logError(1, "%s Interrupt Disabled!\n", tag); + } + return OK; + } else { + logError(1, "%s %s: Impossible get client irq... ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + +} + +/** + * Disable the interrupt async so the ISR of the driver can not be called + * @return OK if success or an error code which specify the type of error encountered + */ +int fts_disableInterruptNoSync(void) +{ + if (getClient() != NULL) { + spin_lock_irq(&fts_int); + logError(0, "%s Number of disable = %d \n", tag, + disable_irq_count); + if (disable_irq_count == 0) { + logError(0, "%s Executing Disable... \n", tag); + disable_irq_nosync(getClient()->irq); + disable_irq_count++; + } + + spin_unlock_irq(&fts_int); + logError(0, "%s Interrupt No Sync Disabled!\n", tag); + return OK; + } else { + logError(1, "%s %s: Impossible get client irq... ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } +} + +/** + * Reset the disable_irq count + * @return OK + */ +int fts_resetDisableIrqCount(void) +{ + disable_irq_count = 0; + return OK; +} + +/** + * Enable the interrupt so the ISR of the driver can be called + * @return OK if success or an error code which specify the type of error encountered + */ +int fts_enableInterrupt(void) +{ + if (getClient() != NULL) { + + logError(0, "%s Number of re-enable = %d \n", tag, + disable_irq_count); + while (disable_irq_count > 0) { + logError(0, "%s Excecuting Enable... \n", tag); + enable_irq(getClient()->irq); + disable_irq_count--; + logError(1, "%s Interrupt Enabled!\n", tag); + } + return OK; + } else { + logError(1, "%s %s: Impossible get client irq... ERROR %08X\n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } +} + +/** +* Check if there is a crc error in the IC which prevent the fw to run. +* @return OK if no CRC error, or a number >OK according the CRC error found +*/ +int fts_crc_check(void) +{ + u8 val; + u8 crc_status; + int res; + u8 error_to_search[6] = { EVT_TYPE_ERROR_CRC_CFG_HEAD, EVT_TYPE_ERROR_CRC_CFG, + EVT_TYPE_ERROR_CRC_CX, EVT_TYPE_ERROR_CRC_CX_HEAD, + EVT_TYPE_ERROR_CRC_CX_SUB, + EVT_TYPE_ERROR_CRC_CX_SUB_HEAD + }; + + res = + fts_writeReadU8UX(FTS_CMD_HW_REG_R, ADDR_SIZE_HW_REG, ADDR_CRC, + &val, 1, DUMMY_HW_REG); + if (res < OK) { + logError(1, "%s %s Cannot read crc status ERROR %08X\n", tag, + __func__, res); + return res; + } + + crc_status = val & CRC_MASK; + if (crc_status != OK) { + logError(1, "%s %s CRC ERROR = %02X \n", tag, __func__, + crc_status); + return CRC_CODE; + } + + logError(1, "%s %s: Verifying if Config CRC Error...\n", tag, __func__); + res = fts_system_reset(); + if (res >= OK) { + res = pollForErrorType(error_to_search, 2); + if (res < OK) { + logError(1, "%s %s: No Config CRC Error Found! \n", tag, + __func__); + logError(1, "%s %s: Verifying if Cx CRC Error...\n", + tag, __func__); + res = pollForErrorType(&error_to_search[2], 4); + if (res < OK) { + logError(1, "%s %s: No Cx CRC Error Found! \n", + tag, __func__); + return OK; + } else { + logError(1, + "%s %s: Cx CRC Error found! CRC ERROR = %02X\n", + tag, __func__, res); + return CRC_CX; + } + } else { + logError(1, + "%s %s: Config CRC Error found! CRC ERROR = %02X\n", + tag, __func__, res); + return CRC_CONFIG; + } + } else { + logError(1, + "%s %s: Error while executing system reset! ERROR %08X\n", + tag, __func__, res); + return res; + } + + return OK; +} + +/** + * Request a host data and use the sync method to understand when the FW load it + * @param type the type ID of host data to load (@link load_opt Load Host Data Option @endlink) + * @return OK if success or an error code which specify the type of error encountered + */ +int requestSyncFrame(u8 type) +{ + u8 request[3] = { FTS_CMD_SYSTEM, SYS_CMD_LOAD_DATA, type }; + u8 readData[DATA_HEADER] = { 0 }; + int ret, retry = 0, retry2 = 0, time_to_count; + int count, new_count; + + logError(0, "%s %s: Starting to get a sync frame...\n", tag, __func__); + + while (retry2 < RETRY_MAX_REQU_DATA) { + logError(0, "%s %s: Reading count...\n", tag, __func__); + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, + ADDR_FRAMEBUFFER, readData, DATA_HEADER, + DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(0, + "%s %s: Error while reading count! ERROR %08X \n", + tag, __func__, ret | ERROR_REQU_DATA); + ret |= ERROR_REQU_DATA; + retry2++; + continue; + } + + if (readData[0] != HEADER_SIGNATURE) { + logError(1, + "%s %s: Invalid Signature while reading count! ERROR %08X \n", + tag, __func__, ret | ERROR_REQU_DATA); + ret |= ERROR_REQU_DATA; + retry2++; + continue; + } + + count = (readData[3] << 8) | readData[2]; + new_count = count; + logError(0, "%s %s: Base count = %d\n", tag, __func__, count); + + logError(0, "%s %s: Requesting frame %02X attempt = %d \n", + tag, __func__, type, retry2 + 1); + ret = fts_write_dma_safe(request, ARRAY_SIZE(request)); + if (ret >= OK) { + + logError(0, "%s %s: Polling for new count... \n", tag, + __func__); + time_to_count = TIMEOUT_REQU_DATA / TIMEOUT_RESOLUTION; + while (count == new_count && retry < time_to_count) { + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, + BITS_16, ADDR_FRAMEBUFFER, + readData, DATA_HEADER, + DUMMY_FRAMEBUFFER); + if (ret >= OK + && readData[0] == HEADER_SIGNATURE) { + new_count = + ((readData[3] << 8) | readData[2]); + } else { + logError(0, + "%s %s: invalid Signature or can not read count... ERROR %08X \n", + tag, __func__, ret); + } + retry++; + mdelay(TIMEOUT_RESOLUTION); + } + + if (count == new_count) { + logError(1, + "%s %s: New count not received! ERROR %08X \n", + tag, __func__, + ERROR_TIMEOUT | ERROR_REQU_DATA); + ret = ERROR_TIMEOUT | ERROR_REQU_DATA; + } else { + logError(0, + "%s %s: New count found! count = %d! Frame ready! \n", + tag, __func__, new_count); + return OK; + } + } + retry2++; + } + logError(1, "%s %s: Request Data failed! ERROR %08X \n", tag, __func__, + ret); + return ret; +} + +int calculateCRC8(u8 *u8_srcBuff, int size, u8 *crc) +{ + u8 u8_remainder; + u8 bit; + int i = 0; + u8_remainder = 0x00; + + logError(0, "%s %s: Start CRC computing...\n", tag, __func__); + if (size != 0 && u8_srcBuff != NULL) { + for (i = 0; i < size; i++) { + u8_remainder ^= u8_srcBuff[i]; + for (bit = 8; bit > 0; --bit) { + if (u8_remainder & (0x1 << 7)) { + u8_remainder = + (u8_remainder << 1) ^ 0x9B; + } else { + u8_remainder = (u8_remainder << 1); + } + } + } + *crc = u8_remainder; + logError(0, "%s %s: CRC value = %02X\n", tag, __func__, *crc); + return OK; + } else { + logError(1, + "%s %s: Arguments passed not valid! Data pointer = NULL or size = 0 (%d) ERROR %08X\n", + tag, __func__, size, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } +} + +int writeLockDownInfo(u8 *data, int size, u8 lock_id) +{ + int ret, i; + u8 crc_data = 0; + u8 crc_head = 0; + u8 cmd_lockdown_prepare[8] = { LOCKDOWN_SIGNATURE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + u8 cmd_lockdown_crc[4] = { 0x00 }; + u8 lockdown_save[3] = { 0xA4, 0x00, 0x04 }; + u8 *temp = NULL; + u8 error_to_search[4] = { EVT_TYPE_ERROR_LOCKDOWN_FLASH, EVT_TYPE_ERROR_LOCKDOWN_CRC, + EVT_TYPE_ERROR_LOCKDOWN_NO_DATA, + EVT_TYPE_ERROR_LOCKDOWN_WRITE_FULL + }; + + logError(0, "%s %s:enter", tag, __func__); + if (lock_id < 0x70 || lock_id > 0x77 || size <= 0 + || size > LOCKDOWN_LENGTH - 20) { + logError(1, + "%s %s the lock id type is:%02X size:%d not support\n", + tag, __func__, lock_id, size); + return ERROR_LOCKDOWN_CODE; + } + + temp = printHex_data("Lockdown Code = ", data, size); + if (temp != NULL) { + logError(1, "%s: %s", __func__, temp); + kfree(temp); + } + + logError(0, "%s: Writing Lockdown code into the IC ...\n", __func__); + fts_disableInterrupt(); + for (i = 0; i < 3; i++) { + cmd_lockdown_prepare[1] = lock_id; + ret = calculateCRC8(data, size, &crc_data); + if (ret < OK) { + logError(1, + "%s %s: Unable to compute data CRC.. ERROR %08X\n", + tag, __func__, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + logError(0, "%s %s: Get the data CRC value:%02X\n", tag, + __func__, crc_data); + ret = + fts_writeU8UX(LOCKDOWN_WRITEREAD_CMD, BITS_16, + ADDR_LOCKDOWN, cmd_lockdown_prepare, + ARRAY_SIZE(cmd_lockdown_prepare)); + if (ret < OK) { + logError(1, + "%s %s: Unable to write Lockdown data prepare at %d iteration.. ERROR %08X\n", + tag, __func__, i, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + logError(0, "%s %s: Compute 8bit header CRC...\n", tag, + __func__); + + cmd_lockdown_crc[0] = (u8) size; + cmd_lockdown_crc[1] = crc_data; + cmd_lockdown_crc[2] = lock_id; + ret = calculateCRC8(cmd_lockdown_crc, 3, &crc_head); + if (ret < OK) { + logError(1, + "%s %s: Unable to compute head CRC.. ERROR %08X\n", + tag, __func__, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + cmd_lockdown_crc[3] = crc_head; + logError(0, "%s %s: Get the header CRC value:%02X\n", tag, + __func__, crc_head); + + ret = + fts_writeU8UX(LOCKDOWN_WRITEREAD_CMD, BITS_16, + ADDR_LOCKDOWN + LOCKDOWN_DATA_OFFSET - + LOCKDOWN_HEAD_LENGTH, cmd_lockdown_crc, + ARRAY_SIZE(cmd_lockdown_crc)); + if (ret < OK) { + logError(1, + "%s %s: Unable to write Lockdown head at %d iteration.. ERROR %08X\n", + tag, __func__, i, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + mdelay(10); + ret = + fts_writeU8UX(LOCKDOWN_WRITEREAD_CMD, BITS_16, + ADDR_LOCKDOWN + LOCKDOWN_DATA_OFFSET, data, + size); + if (ret < OK) { + logError(1, + "%s %s: Unable to write Lockdown head at %d iteration.. ERROR %08X\n", + tag, __func__, i, ret); + ret = (ret | ERROR_LOCKDOWN_CODE); + continue; + } + mdelay(10); + ret = fts_write_dma_safe(lockdown_save, 3); + mdelay(5); + ret = checkEcho(lockdown_save, 3); + if (ret < OK) { + logError(1, "%s No Echo received.. ERROR %08X !\n", tag, + ret); + continue; + } else { + logError(1, "%s Echo FOUND... OK!\n", tag, ret); + ret = pollForErrorType(error_to_search, 4); + if (ret < OK) { + logError(1, "%s %s: No Error Found! \n", tag, + __func__); + ret = OK; + } else { + logError(1, + "%s %s: have error when write lockdown ERROR = %02X\n", + tag, __func__, ret); + ret = ERROR_LOCKDOWN_CODE; + } + break; + } + } + if (ret < OK) + logError(1, "%s %s end, write lockdown failed\n", tag, __func__, + ret); + else + logError(1, "%s %s end, write lockdown success\n", tag, + __func__, ret); + + fts_enableInterrupt(); + return ret; +} + +int readLockDownInfo(u8 *lockData, u8 lock_id, int size) +{ + int ret = 0, i; + int loaded_cnt = 0; + int loaded_cnt_after = 0; + u8 *temp = NULL; + char *datatemp = NULL; + u8 cmd_lockdown[3] = { 0xA4, 0x06, 0x00 }; + + logError(0, "%s %s:enter", tag, __func__); + if (lock_id < 0x70 || lock_id > 0x77 || size <= 0 + || size > LOCKDOWN_LENGTH - 20) { + logError(1, "%s the lock id type is:%02X not support\n", tag, + lock_id); + return ERROR_LOCKDOWN_CODE; + } + + temp = (u8 *) kmalloc(LOCKDOWN_LENGTH * sizeof(u8), GFP_KERNEL); + if (temp == NULL) { + logError(1, "FTS temp alloc memory failed \n"); + return -ENOMEM; + } + memset(temp, 0, LOCKDOWN_LENGTH * sizeof(u8)); + + fts_disableInterrupt(); + for (i = 0; i < 3; i++) { + ret = + fts_writeReadU8UX(LOCKDOWN_WRITEREAD_CMD, BITS_16, + ADDR_LOCKDOWN, temp, LOCKDOWN_HEAD_LENGTH, + DUMMY_CONFIG); + if (ret < OK) { + logError(1, + "%s %s: error while reading data ERROR %08X \n", + tag, __func__, ret); + goto END; + } + loaded_cnt = (int)((temp[3] & 0xFF) << 8) + (temp[2] & 0xFF); + cmd_lockdown[2] = lock_id; + fts_write_dma_safe(cmd_lockdown, 3); + mdelay(10); + ret = checkEcho(cmd_lockdown, 3); + if (ret < OK) { + logError(1, "%s No Echo received.. ERROR %08X !\n", tag, + ret); + continue; + } else { + logError(1, "%s Echo FOUND... OK!\n", tag, ret); + } + ret = + fts_writeReadU8UX(LOCKDOWN_WRITEREAD_CMD, BITS_16, + ADDR_LOCKDOWN, temp, + size + LOCKDOWN_DATA_OFFSET, + DUMMY_CONFIG); + if (ret < OK) { + logError(1, + "%s %s: error while reading data ERROR %08X \n", + tag, __func__, ret); + goto END; + } + + loaded_cnt_after = + (int)((temp[3] & 0xFF) << 8) + (temp[2] & 0xFF); + if (temp[4] == EVT_TYPE_ERROR_LOCKDOWN_FLASH + || temp[4] == EVT_TYPE_ERROR_LOCKDOWN_NO_DATA) { + logError(1, + "%s %s: can not read the lockdown code ERROR type:%02X\n", + tag, __func__, temp[4]); + ret = ERROR_LOCKDOWN_CODE; + goto END; + } + + logError(1, + "%s %s signature:%02X id:%02X %02X beforecnt:%d,aftercnt:%d\n", + tag, __func__, temp[0], temp[1], lock_id, loaded_cnt, + loaded_cnt_after); + if (loaded_cnt_after == loaded_cnt + 1) { + ret = OK; + memcpy(lockData, &temp[LOCKDOWN_DATA_OFFSET], size); + break; + } + + } + + datatemp = printHex_data("Lockdown Code = ", lockData, size); + if (datatemp != NULL) { + logError(1, "%s %s", tag, datatemp); + kfree(datatemp); + } + +END: + fts_enableInterrupt(); + kfree(temp); + return ret; +} + +int fts_get_lockdown_info(u8 *lockData, struct fts_ts_info *info) +{ + int ret = 0, i; + int loaded_cnt = 0; + u8 lock_id = FTS_CMD_LOCKDOWN_ID; + int size = FTS_LOCKDOWN_SIZE; + int loaded_cnt_after = 0; + u8 *temp = NULL; + u8 cmd_lockdown[3] = { 0xA4, 0x06, 0x00 }; + char *datatemp = NULL; + + if (info == NULL) + return ERROR_LOCKDOWN_CODE; + if (info->lockdown_is_ok) { + logError(1, "%s %s aleady get,skip\n", tag, __func__); + return OK; + } + logError(0, "%s %s:enter", tag, __func__); + if (lock_id < 0x70 || lock_id > 0x77) { + logError(1, "%s the lock id type is not support\n", tag); + return ERROR_LOCKDOWN_CODE; + } + + temp = (u8 *) kmalloc(1024 * sizeof(u8), GFP_KERNEL); + if (temp == NULL) { + logError(1, "FTS temp alloc memory failed \n"); + return -ENOMEM; + } + memset(temp, 0, 1024 * sizeof(u8)); + + fts_disableInterrupt(); + + for (i = 0; i < LOCKDOWN_CODE_RETRY; i++) { + + ret = + fts_writeReadU8UX(LOCKDOWN_WRITEREAD_CMD, BITS_16, + ADDR_LOCKDOWN, temp, LOCKDOWN_HEAD_LENGTH, + DUMMY_CONFIG); + if (ret < OK) { + logError(1, + "%s %s: error while reading data ERROR %08X \n", + tag, __func__, ret); + goto END; + } + loaded_cnt = (int)((temp[3] & 0xFF) << 8) + (temp[2] & 0xFF); + cmd_lockdown[2] = lock_id; + fts_write_dma_safe(cmd_lockdown, 3); + mdelay(10); + ret = checkEcho(cmd_lockdown, 3); + if (ret < OK) { + logError(1, "%s No Echo received.. ERROR %08X !\n", tag, + ret); + continue; + } else { + logError(1, "%s Echo FOUND... OK!\n", tag, ret); + } + ret = + fts_writeReadU8UX(LOCKDOWN_WRITEREAD_CMD, BITS_16, + ADDR_LOCKDOWN, temp, + size + LOCKDOWN_DATA_OFFSET, + DUMMY_CONFIG); + if (ret < OK) { + logError(1, + "%s %s: error while reading data ERROR %08X \n", + tag, __func__, ret); + goto END; + } + + loaded_cnt_after = + (int)((temp[3] & 0xFF) << 8) + (temp[2] & 0xFF); + if (temp[4] == EVT_TYPE_ERROR_LOCKDOWN_FLASH + || temp[4] == EVT_TYPE_ERROR_LOCKDOWN_NO_DATA) { + logError(1, + "%s %s: can not read the lockdown code ERROR type:%02X\n", + tag, __func__, temp[4]); + ret = ERROR_LOCKDOWN_CODE; + goto END; + } + + logError(1, + "%s %s signature:%02X id:%02X %02X beforecnt:%d,aftercnt:%d\n", + tag, __func__, temp[0], temp[1], lock_id, loaded_cnt, + loaded_cnt_after); + if (loaded_cnt_after == loaded_cnt + 1) { + ret = OK; + memcpy(lockData, &temp[LOCKDOWN_DATA_OFFSET], size); + break; + } + + } + + datatemp = printHex_data("Lockdown Code = ", lockData, size); + if (datatemp != NULL) { + logError(0, "%s %s", tag, datatemp); + kfree(datatemp); + } + +END: + fts_enableInterrupt(); + kfree(temp); + return ret; + +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsCore.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsCore.h new file mode 100644 index 000000000000..0022ceacc3d2 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsCore.h @@ -0,0 +1,180 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS Core definitions * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsCore.h +* \brief Contains all the definitions and structs of Core functionalities +*/ + +#ifndef FTS_CORE_H +#define FTS_CORE_H + +#include "ftsHardware.h" +#include "ftsSoftware.h" +#include "../fts.h" + +/*HW DATA*/ +#define GPIO_NOT_DEFINED -1 /*value assumed by reset_gpio when the reset pin of the IC is not connected*/ + +#define ADDR_SIZE_HW_REG BITS_32 /*value of AddrSize for Hw register in FTI @see AddrSize*/ + +#define DATA_HEADER 4 /*size in byte of the header loaded with the data in the frambuffer*/ +#define LOCKDOWN_CODE_RETRY 2 +/** + * Type of CRC errors + */ +typedef enum { + CRC_CODE = 1, /*CRC in the code section*/ + CRC_CONFIG = 2, /*CRC in the config section*/ + CRC_CX = 3, /*CRC in the cx section*/ + CRC_PANEL = 4 /*CRC in the panel section*/ +} CRC_Error; + +/*CHIP INFO*/ +/** @defgroup system_info System Info +* System Info Data collect the most important informations about hw and fw +* @{ +*/ +#define SYS_INFO_SIZE 208 /*Size in bytes of System Info data*/ +#define DIE_INFO_SIZE 16 /*num bytes of die info*/ +#define EXTERNAL_RELEASE_INFO_SIZE 8 /*num bytes of external release in config*/ +#define RELEASE_INFO_SIZE (EXTERNAL_RELEASE_INFO_SIZE + 8) /*num bytes of release info in sys info (first bytes are external release)*/ +/** @}*/ + +/*RETRY MECHANISM*/ +#define RETRY_MAX_REQU_DATA 2 /*Max number of attemps performed when requesting data*/ +#define RETRY_SYSTEM_RESET 3 /*Max number of attemps performed to reset the IC*/ + +/*LOCKDOWN INFO*/ +#define LOCKDOWN_LENGTH 384 +#define LOCKDOWN_HEAD_LENGTH 4 +#define LOCKDOWN_DATA_OFFSET 20 +#define LOCKDOWN_SIGNATURE 0x5A +#define ADDR_LOCKDOWN ((u64)0x0000000000000000) +#define LOCKDOWN_WRITEREAD_CMD 0xA6 + +/** @addtogroup system_info +* @{ +*/ + +/** + * Struct which contains fundamental informations about the chip and its configuration + */ +typedef struct { + u16 u16_apiVer_rev; /*API revision version*/ + u8 u8_apiVer_minor; /*API minor version*/ + u8 u8_apiVer_major; /*API major version*/ + u16 u16_chip0Ver; /*Dev0 version*/ + u16 u16_chip0Id; /*Dev0 ID*/ + u16 u16_chip1Ver; /*Dev1 version*/ + u16 u16_chip1Id; /*Dev1 ID*/ + u16 u16_fwVer; /*Fw version*/ + u16 u16_svnRev; /*SVN Revision*/ + u16 u16_cfgVer; /*Config Version*/ + u16 u16_cfgProgectId; /*Config Project ID*/ + u16 u16_cxVer; /*Cx Version*/ + u16 u16_cxProjectId; /*Cx Project ID*/ + u8 u8_cfgAfeVer; /*AFE version in Config*/ + u8 u8_cxAfeVer; /*AFE version in CX*/ + u8 u8_panelCfgAfeVer; /*AFE version in PanelMem*/ + u8 u8_protocol; /*Touch Report Protocol*/ + u8 u8_dieInfo[DIE_INFO_SIZE]; /*Die information*/ + u8 u8_releaseInfo[RELEASE_INFO_SIZE]; /*Release information*/ + u32 u32_fwCrc; /*Crc of FW*/ + u32 u32_cfgCrc; /*Crc of config*/ + + u16 u16_scrResX; /*X resolution on main screen*/ + u16 u16_scrResY; /*Y resolution on main screen*/ + u8 u8_scrTxLen; /*Tx length*/ + u8 u8_scrRxLen; /*Rx length*/ + u8 u8_keyLen; /*Key Len*/ + u8 u8_forceLen; /*Force Len*/ + + u16 u16_dbgInfoAddr; /*Offset of debug Info structure*/ + + u16 u16_msTchRawAddr; /*Offset of MS touch raw frame*/ + u16 u16_msTchFilterAddr; /*Offset of MS touch filter frame*/ + u16 u16_msTchStrenAddr; /*Offset of MS touch strength frame*/ + u16 u16_msTchBaselineAddr; /*Offset of MS touch baseline frame*/ + + u16 u16_ssTchTxRawAddr; /*Offset of SS touch force raw frame*/ + u16 u16_ssTchTxFilterAddr; /*Offset of SS touch force filter frame*/ + u16 u16_ssTchTxStrenAddr; /*Offset of SS touch force strength frame*/ + u16 u16_ssTchTxBaselineAddr; /*Offset of SS touch force baseline frame*/ + + u16 u16_ssTchRxRawAddr; /*Offset of SS touch sense raw frame*/ + u16 u16_ssTchRxFilterAddr; /*Offset of SS touch sense filter frame*/ + u16 u16_ssTchRxStrenAddr; /*Offset of SS touch sense strength frame*/ + u16 u16_ssTchRxBaselineAddr; /*Offset of SS touch sense baseline frame*/ + + u16 u16_keyRawAddr; /*Offset of key raw frame*/ + u16 u16_keyFilterAddr; /*Offset of key filter frame*/ + u16 u16_keyStrenAddr; /*Offset of key strength frame*/ + u16 u16_keyBaselineAddr; /*Offset of key baseline frame*/ + + u16 u16_frcRawAddr; /*Offset of force touch raw frame*/ + u16 u16_frcFilterAddr; /*Offset of force touch filter frame*/ + u16 u16_frcStrenAddr; /*Offset of force touch strength frame*/ + u16 u16_frcBaselineAddr; /*Offset of force touch baseline frame*/ + + u16 u16_ssHvrTxRawAddr; /*Offset of SS hover Force raw frame*/ + u16 u16_ssHvrTxFilterAddr; /*Offset of SS hover Force filter frame*/ + u16 u16_ssHvrTxStrenAddr; /*Offset of SS hover Force strength frame*/ + u16 u16_ssHvrTxBaselineAddr; /*Offset of SS hover Force baseline frame*/ + + u16 u16_ssHvrRxRawAddr; /*Offset of SS hover Sense raw frame*/ + u16 u16_ssHvrRxFilterAddr; /*Offset of SS hover Sense filter frame*/ + u16 u16_ssHvrRxStrenAddr; /*Offset of SS hover Sense strength frame*/ + u16 u16_ssHvrRxBaselineAddr; /*Offset of SS hover Sense baseline frame*/ + + u16 u16_ssPrxTxRawAddr; /*Offset of SS proximity force raw frame*/ + u16 u16_ssPrxTxFilterAddr; /*Offset of SS proximity force filter frame*/ + u16 u16_ssPrxTxStrenAddr; /*Offset of SS proximity force strength frame*/ + u16 u16_ssPrxTxBaselineAddr; /*Offset of SS proximity force baseline frame*/ + + u16 u16_ssPrxRxRawAddr; /*Offset of SS proximity sense raw frame*/ + u16 u16_ssPrxRxFilterAddr; /*Offset of SS proximity sense filter frame*/ + u16 u16_ssPrxRxStrenAddr; /*Offset of SS proximity sense strength frame*/ + u16 u16_ssPrxRxBaselineAddr; /*Offset of SS proximity sense baseline frame*/ +} SysInfo; + +/** @}*/ + +int initCore(struct fts_ts_info *info); +void setResetGpio(int gpio); +int fts_system_reset(void); +int isSystemResettedUp(void); +int isSystemResettedDown(void); +void setSystemResetedUp(int val); +void setSystemResetedDown(int val); +int pollForEvent(int *event_to_search, int event_bytes, u8 *readData, int time_to_wait); +int checkEcho(u8 *cmd, int size); +int setScanMode(u8 mode, u8 settings); +int setFeatures(u8 feat, u8 *settings, int size); +int defaultSysInfo(int i2cError); +int writeSysCmd(u8 sys_cmd, u8 *sett, int size); +int readSysInfo(int request); +int readConfig(u16 offset, u8 *outBuf, int len); +int fts_disableInterrupt(void); +int fts_disableInterruptNoSync(void); +int fts_resetDisableIrqCount(void); +int fts_enableInterrupt(void); +int fts_crc_check(void); +int requestSyncFrame(u8 type); +int fts_get_lockdown_info(u8 *lockData, struct fts_ts_info *info); +int writeLockDownInfo(u8 *data, int size, u8 lock_id); +int readLockDownInfo(u8 *lockData, u8 lock_id, int size); + +#endif /* FTS_CORE_H */ diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsError.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsError.c new file mode 100644 index 000000000000..0435875f8533 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsError.c @@ -0,0 +1,357 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS error/info kernel log reporting * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsError.c +* \brief Contains all the function which handle with Error conditions +*/ + +#include +#include +#include +#include +#include + +#include "../fts.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsIO.h" +#include "ftsTool.h" +#include "ftsCompensation.h" + +static ErrorList errors; + +/** +* Print messages in the kernel log +* @param force if 1, the log is printed always otherwise only if DEBUG is defined, the log will be printed +* @param msg string containing the message to print +* @param ... additional parameters that are used in msg according the format of printf +*/ +void logError(int force, const char *msg, ...) +{ + if (force == 1 +#ifdef DEBUG + || 1 +#endif + ) { + va_list args; + va_start(args, msg); + vprintk(msg, args); + va_end(args); + } +} + +/** +* Check if an error code is related to an I2C failure +* @param error error code to check +* @return 1 if the first level error code is I2C related otherwise 0 +*/ +int isI2cError(int error) +{ + if (((error & 0x000000FF) >= (ERROR_BUS_R & 0x000000FF)) && + ((error & 0x000000FF) <= (ERROR_BUS_O & 0x000000FF))) + return 1; + else + return 0; +} + +/** + * Dump in the kernel log some debug info in case of FW hang + * @param outBuf (optional)pointer to bytes array where to copy the debug info, if NULL the data will just printed on the kernel log + * @param size dimension in bytes of outBuf, if > ERROR_DUMP_ROW_SIZE*ERROR_DUMP_COL_SIZE, only the first ERROR_DUMP_ROW_SIZE*ERROR_DUMP_COL_SIZE bytes will be copied + * @return OK if success or an error code which specify the type of error encountered + */ +int dumpErrorInfo(u8 *outBuf, int size) +{ + int ret, i; + u8 data[ERROR_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE] = { 0 }; + u32 sign = 0; + + logError(0, "%s %s: Starting dump of error info...\n", tag, __func__); + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, ADDR_ERROR_DUMP, + data, ERROR_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE, + DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, "%s %s: reading data ERROR %08X\n", tag, __func__, + ret); + return ret; + } else { + if (outBuf != NULL) { + sign = + size > + ERROR_DUMP_ROW_SIZE * + ERROR_DUMP_COL_SIZE ? ERROR_DUMP_ROW_SIZE * + ERROR_DUMP_COL_SIZE : size; + memcpy(outBuf, data, sign); + logError(0, + "%s %s: error info copied in the buffer! \n", + tag, __func__); + } + logError(1, "%s %s: Error Info = \n", tag, __func__); + u8ToU32(data, &sign); + if (sign != ERROR_DUMP_SIGNATURE) + logError(1, + "%s %s: Wrong Error Signature! Data may be invalid! \n", + tag, __func__); + else + logError(1, + "%s %s: Error Signature OK! Data are valid! \n", + tag, __func__); + + for (i = 0; i < ERROR_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE; i++) { + if (i % ERROR_DUMP_COL_SIZE == 0) { + logError(1, KERN_ERR "\n%s %s: %d) ", tag, + __func__, i / ERROR_DUMP_COL_SIZE); + } + logError(1, "%02X ", data[i]); + } + logError(1, "\n"); + + logError(0, "%s %s: dump of error info FINISHED!\n", tag, + __func__); + return OK; + } + +} + +/** +* Implement recovery strategies to be used when an error event is found while polling the FIFO +* @param event error event found during the polling +* @param size size of event +* @return OK if the error event doesn't require any action or the recovery strategy doesn't have any impact in the possible procedure that trigger the error, otherwise return an error code which specify the kind of error encountered. If ERROR_HANDLER_STOP_PROC the calling function must stop! +*/ +int errorHandler(u8 *event, int size) +{ + int res = OK; + struct fts_ts_info *info = NULL; + + if (getDev() != NULL) + info = dev_get_drvdata(getDev()); + + if (info != NULL && event != NULL && size > 1 + && event[0] == EVT_ID_ERROR) { + logError(0, "%s errorHandler: Starting handling...\n", tag); + addErrorIntoList(event, size); + switch (event[1]) { + case EVT_TYPE_ERROR_ESD: + res = fts_chip_powercycle(info); + if (res < OK) { + logError(1, + "%s errorHandler: Error performing powercycle ERROR %08X\n", + tag, res); + } + + res = fts_system_reset(); + if (res < OK) { + logError(1, + "%s errorHandler: Cannot reset the device ERROR %08X\n", + tag, res); + } + res = (ERROR_HANDLER_STOP_PROC | res); + break; + + case EVT_TYPE_ERROR_WATCHDOG: + dumpErrorInfo(NULL, 0); + res = fts_system_reset(); + if (res < OK) { + logError(1, + "%s errorHandler: Cannot reset the device ERROR %08X\n", + tag, res); + } + res = (ERROR_HANDLER_STOP_PROC | res); + break; + + case EVT_TYPE_ERROR_ITO_FORCETOGND: + logError(1, "%s errorHandler: Force Short to GND!\n", + tag); + break; + case EVT_TYPE_ERROR_ITO_SENSETOGND: + logError(1, "%s errorHandler: Sense short to GND! \n", + tag); + break; + case EVT_TYPE_ERROR_ITO_FORCETOVDD: + logError(1, "%s errorHandler: Force short to VDD!\n", + tag); + break; + case EVT_TYPE_ERROR_ITO_SENSETOVDD: + logError(1, "%s errorHandler: Sense short to VDD!\n", + tag); + break; + case EVT_TYPE_ERROR_ITO_FORCE_P2P: + logError(1, + "%s errorHandler: Force Pin to Pin Short!\n", + tag); + break; + case EVT_TYPE_ERROR_ITO_SENSE_P2P: + logError(1, + "%s errorHandler: Sense Pin to Pin Short!\n", + tag); + break; + case EVT_TYPE_ERROR_ITO_FORCEOPEN: + logError(1, "%s errorHandler: Force Open !\n", tag); + break; + case EVT_TYPE_ERROR_ITO_SENSEOPEN: + logError(1, "%s errorHandler: Sense Open !\n", tag); + break; + case EVT_TYPE_ERROR_ITO_KEYOPEN: + logError(1, "%s errorHandler: Key Open !\n", tag); + break; + + default: + logError(0, "%s errorHandler: No Action taken! \n", + tag); + break; + + } + logError(0, "%s errorHandler: handling Finished! res = %08X\n", + tag, res); + return res; + } else { + logError(1, + "%s errorHandler: event Null or not correct size! ERROR %08X \n", + tag, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + +} + +/** +* Add an error event into the Error List +* @param event error event to add +* @param size size of event +* @return OK +*/ +int addErrorIntoList(u8 *event, int size) +{ + int i = 0; + + logError(0, "%s Adding error in to ErrorList... \n", tag); + + memcpy(&errors.list[errors.last_index * FIFO_EVENT_SIZE], event, size); + i = FIFO_EVENT_SIZE - size; + if (i > 0) { + logError(0, + "%s Filling last %d bytes of the event with zero...\n", + tag, i); + memset(&errors.list[errors.last_index * FIFO_EVENT_SIZE + size], + 0, i); + } + logError(0, "%s Adding error in to ErrorList... FINISHED!\n", tag); + + errors.count += 1; + if (errors.count > FIFO_DEPTH) + logError(1, + "%s ErrorList is going in overflow... the first %d event(s) were override!\n", + tag, errors.count - FIFO_DEPTH); + errors.last_index = (errors.last_index + 1) % FIFO_DEPTH; + + return OK; +} + +/** +* Reset the Error List setting the count and last_index to 0. +* @return OK +*/ +int resetErrorList(void) +{ + errors.count = 0; + errors.last_index = 0; + memset(errors.list, 0, FIFO_DEPTH * FIFO_EVENT_SIZE); + return OK; +} + +/** +* Get the number of error events copied into the Error List +* @return the number of error events into the Error List +*/ +int getErrorListCount(void) +{ + if (errors.count > FIFO_DEPTH) + return FIFO_DEPTH; + else + return errors.count; +} + + +/** +* Scroll the Error List looking for the event specified +* @param event_to_search event_to_search pointer to an array of int where each element correspond to a byte of the event to find. If the element of the array has value -1, the byte of the event, in the same position of the element is ignored. +* @param event_bytes size of event_to_search +* @return a value >=0 if the event is found which represent the index of the Error List where the event is located otherwise an error code +*/ +int pollErrorList(int *event_to_search, int event_bytes) +{ + int i = 0, j = 0, find = 0; + int count = getErrorListCount(); + + logError(0, "%s Starting to poll ErrorList... \n", tag); + while (find != 1 && i < count) { + find = 1; + for (j = 0; j < event_bytes; j++) { + + if (event_to_search[i] != -1 + && (int)errors.list[i * FIFO_EVENT_SIZE + j] != + event_to_search[i]) { + find = 0; + break; + } + } + i++; + } + if (find == 1) { + logError(1, "%s Error Found into ErrorList! \n", tag); + return i - 1; + } else { + logError(0, "%s Error Not Found into ErrorList! ERROR %08X \n", + tag, ERROR_TIMEOUT); + return ERROR_TIMEOUT; + } +} + +/** +* Poll the Error List looking for any error types passed in the arguments. Return at the first match! +* @param list pointer to a list of error types to look for +* @param size size of list +* @return error type found if success or ERROR_TIMEOUT +*/ +int pollForErrorType(u8 *list, int size) +{ + int i = 0, j = 0, find = 0; + int count = getErrorListCount(); + + logError(0, "%s %s: Starting to poll ErrorList... count = %d \n", tag, + __func__, count); + while (find != 1 && i < count) { + for (j = 0; j < size; j++) { + if (list[j] == errors.list[i * FIFO_EVENT_SIZE + 1]) { + find = 1; + break; + } + } + i++; + } + if (find == 1) { + logError(1, "%s %s: Error Type %02X into ErrorList! \n", tag, + __func__, list[j]); + return list[j]; + } else { + logError(0, + "%s %s: Error Type Not Found into ErrorList! ERROR %08X \n", + tag, __func__, ERROR_TIMEOUT); + return ERROR_TIMEOUT; + } +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsError.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsError.h new file mode 100644 index 000000000000..206a0b3ad400 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsError.h @@ -0,0 +1,145 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS error/info kernel log reporting * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsError.h +* \brief Contains all the definitions and structs which refer to Error conditions +*/ + +#ifndef FTS_ERROR_H +#define FTS_ERROR_H + +#include "ftsHardware.h" +#include "ftsSoftware.h" + +/** @defgroup error_codes Error Codes + * Error codes that can be reported by the driver functions. + * An error code is made up by 4 bytes, each byte indicate a logic error level.\n + * From the LSB to the MSB, the logic level increase going from a low level error (I2C,TIMEOUT) to an high level error (flashing procedure fail, production test fail etc) + * @{ + */ + +/*FIRST LEVEL ERROR CODE*/ +/** @defgroup first_level First Level Error Code +* @ingroup error_codes +* Errors related to low level operation which are not under control of driver, such as: communication protocol (I2C/SPI), timeout, file operations ... +* @{ +*/ +#define OK ((int)0x00000000) /*No ERROR*/ +#define ERROR_ALLOC ((int)0x80000001) /*allocation of memory failed*/ +#define ERROR_BUS_R ((int)0x80000002) /*i2c/spi read failed*/ +#define ERROR_BUS_W ((int)0x80000003) /*i2c/spi write failed*/ +#define ERROR_BUS_WR ((int)0x80000004) /*i2c/spi write/read failed*/ +#define ERROR_BUS_O ((int)0x80000005) /*error during opening an i2c device*/ +#define ERROR_OP_NOT_ALLOW ((int)0x80000006) /*operation not allowed*/ +#define ERROR_TIMEOUT ((int)0x80000007) /*timeout expired! exceed the max number of retries or the max waiting time*/ +#define ERROR_FILE_NOT_FOUND ((int)0x80000008) /*the file that i want to open is not found*/ +#define ERROR_FILE_PARSE ((int)0x80000009) /*error during parsing the file*/ +#define ERROR_FILE_READ ((int)0x8000000A) /*error during reading the file*/ +#define ERROR_LABEL_NOT_FOUND ((int)0x8000000B) /*label not found*/ +#define ERROR_FW_NO_UPDATE ((int)0x8000000C) /*fw in the chip newer than the one in the memmh*/ +#define ERROR_FLASH_UNKNOWN ((int)0x8000000D) /*flash status busy or unknown*/ +/** @}*/ + +/*SECOND LEVEL ERROR CODE */ +/** @defgroup second_level Second Level Error Code +* @ingroup error_codes +* Errors related to simple logic operations in the IC which require one command or which are part of a more complex procedure +* @{ +*/ +#define ERROR_DISABLE_INTER ((int)0x80000200) /*unable to disable the interrupt*/ +#define ERROR_ENABLE_INTER ((int)0x80000300) /*unable to activate the interrup*/ +#define ERROR_READ_CONFIG ((int)0x80000400) /*failed to read config memory*/ +#define ERROR_GET_OFFSET ((int)0x80000500) /*unable to read an offset from memory*/ +#define ERROR_GET_FRAME_DATA ((int)0x80000600) /*unable to retrieve the data of a required frame*/ +#define ERROR_DIFF_DATA_TYPE ((int)0x80000700) /*FW answers with an event that has a different address respect the request done*/ +#define ERROR_WRONG_DATA_SIGN ((int)0x80000800) /*the signature of the host data is not HEADER_SIGNATURE*/ +#define ERROR_SET_SCAN_MODE_FAIL ((int)0x80000900) /*setting the scanning mode failed (sense on/off etc...)*/ +#define ERROR_SET_FEATURE_FAIL ((int)0x80000A00) /*setting a specific feature failed*/ +#define ERROR_SYSTEM_RESET_FAIL ((int)0x80000B00) /*the comand SYSTEM RESET failed*/ +#define ERROR_FLASH_NOT_READY ((int)0x80000C00) /*flash status not ready within a timeout*/ +#define ERROR_FW_VER_READ ((int)0x80000D00) /*unable to retrieve fw_vers or the config_id*/ +#define ERROR_GESTURE_ENABLE_FAIL ((int)0x80000E00) /*unable to enable/disable the gesture*/ +#define ERROR_GESTURE_START_ADD ((int)0x80000F00) /*unable to start to add custom gesture*/ +#define ERROR_GESTURE_FINISH_ADD ((int)0x80001000) /*unable to finish to add custom gesture*/ +#define ERROR_GESTURE_DATA_ADD ((int)0x80001100) /*unable to add custom gesture data*/ +#define ERROR_GESTURE_REMOVE ((int)0x80001200) /*unable to remove custom gesture data*/ +#define ERROR_FEATURE_ENABLE_DISABLE ((int)0x80001300) /*unable to enable/disable a feature mode in the IC*/ +#define ERROR_NOISE_PARAMETERS ((int)0x80001400) /*unable to set/read noise parameter in the IC*/ +#define ERROR_CH_LEN ((int)0x80001500) /*unable to retrieve the force and/or sense length*/ +/** @}*/ + +/*THIRD LEVEL ERROR CODE */ +/** @defgroup third_level Third Level Error Code +* @ingroup error_codes +* Errors related to logic operations in the IC which require more commands/steps or which are part of a more complex procedure +* @{ +*/ +#define ERROR_REQU_COMP_DATA ((int)0x80010000) /*compensation data request failed*/ +#define ERROR_REQU_DATA ((int)0x80020000) /*data request failed*/ +#define ERROR_COMP_DATA_HEADER ((int)0x80030000) /*unable to retrieve the compensation data header*/ +#define ERROR_COMP_DATA_GLOBAL ((int)0x80040000) /*unable to retrieve the global compensation data*/ +#define ERROR_COMP_DATA_NODE ((int)0x80050000) /*unable to retrieve the compensation data for each node*/ +#define ERROR_TEST_CHECK_FAIL ((int)0x80060000) /*check of production limits or of fw answers failed*/ +#define ERROR_MEMH_READ ((int)0x80070000) /*memh reading failed*/ +#define ERROR_FLASH_BURN_FAILED ((int)0x80080000) /*flash burn failed*/ +#define ERROR_MS_TUNING ((int)0x80090000) /*ms tuning failed*/ +#define ERROR_SS_TUNING ((int)0x800A0000) /*ss tuning failed*/ +#define ERROR_LP_TIMER_TUNING ((int)0x800B0000) /*lp timer calibration failed*/ +#define ERROR_SAVE_CX_TUNING ((int)0x800C0000) /*save cx data to flash failed*/ +#define ERROR_HANDLER_STOP_PROC ((int)0x800D0000) /*stop the poll of the FIFO if particular errors are found*/ +#define ERROR_CHECK_ECHO_FAIL ((int)0x800E0000) /*unable to retrieve echo event*/ +#define ERROR_GET_FRAME ((int)0x800F0000) /*unable to get frame*/ +/** @}*/ + +/*FOURTH LEVEL ERROR CODE*/ +/** @defgroup fourth_level Fourth Level Error Code +* @ingroup error_codes +* Errors related to the highest logic operations in the IC which have an important impact on the driver flow or which require several commands and steps to be executed +* @{ +*/ +#define ERROR_PROD_TEST_DATA ((int)0x81000000) /*production data test failed*/ +#define ERROR_FLASH_PROCEDURE ((int)0x82000000) /*fw update procedure failed*/ +#define ERROR_PROD_TEST_ITO ((int)0x83000000) /*production ito test failed*/ +#define ERROR_PROD_TEST_INITIALIZATION ((int)0x84000000) /*production initialization test failed*/ +#define ERROR_GET_INIT_STATUS ((int)0x85000000) /*mismatch of the MS or SS tuning_version*/ +#define ERROR_LOCKDOWN_CODE ((int)0x80001600) /*unable to write/rewrite/read lockdown code in the IC*/ + +#define EVT_TYPE_ERROR_LOCKDOWN_FLASH 0x30 /*FW shall not proceed with any flash write/read*/ +#define EVT_TYPE_ERROR_LOCKDOWN_CRC 0x31 /*FW shall discard the record and do not write to flash*/ +#define EVT_TYPE_ERROR_LOCKDOWN_NO_DATA 0x32 /*No data of this type exisitng in flash*/ +#define EVT_TYPE_ERROR_LOCKDOWN_WRITE_FULL 0x33 /*FW shall not write this new record to flash*/ +/** @}*/ + +/** +* Struct which store an ordered list of the errors events encountered during the polling of a FIFO. +* The max number of error events that can be stored is equal to FIFO_DEPTH +*/ +typedef struct { + u8 list[FIFO_DEPTH * FIFO_EVENT_SIZE]; /*byte array which contains the series of error events encountered from the last reset of the list.*/ + int count; /*number of error events stored in the list*/ + int last_index; /*index of the list where will be stored the next error event. Subtract -1 to have the index of the last error event!*/ +} ErrorList; + +void logError(int force, const char *msg, ...); +int isI2cError(int error); +int dumpErrorInfo(u8 *outBuf, int size); +int errorHandler(u8 *event, int size); +int addErrorIntoList(u8 *event, int size); +int getErrorListCount(void); +int resetErrorList(void); +int pollErrorList(int *event_to_search, int event_bytes); +int pollForErrorType(u8 *list, int size); +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsFlash.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsFlash.c new file mode 100644 index 000000000000..2b3e6766cbf9 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsFlash.c @@ -0,0 +1,1032 @@ +/* + + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS API for Flashing the IC * + * * + ************************************************************************** + ************************************************************************** + + */ + +/*! +* \file ftsFlash.c +* \brief Contains all the functions to handle the FW update process +*/ + +#include "ftsCore.h" +#include "ftsCompensation.h" +#include "ftsError.h" +#include "ftsFlash.h" +#include "ftsFrame.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTest.h" +#include "ftsTime.h" +#include "ftsTool.h" +#include "../fts.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef FW_H_FILE +#include "../fts_fw.h" +#endif + +extern SysInfo systemInfo; +extern struct fts_ts_info *fts_info; + +/** + * Read the fw version and config id from the chip + * @param fw_vers pointer to the variable which will contains the fw version + * @param config_id pointer to the variable which will contains the config id + * @return OK if success or an error code which specify the type of error encountered + */ +int getFirmwareVersion(u16 *fw_vers, u16 *config_id) +{ + u8 fwvers[DCHIP_FW_VER_BYTE]; + u8 confid[CONFIG_ID_BYTE]; + int res; + + res = + fts_writeReadU8UX(FTS_CMD_HW_REG_R, ADDR_SIZE_HW_REG, + ADDR_DCHIP_FW_VER, fwvers, DCHIP_FW_VER_BYTE, + DUMMY_HW_REG); + if (res < OK) { + logError(1, + "%s getFirmwareVersion: unable to read fw_version ERROR %08X\n", + tag, ERROR_FW_VER_READ); + return (res | ERROR_FW_VER_READ); + } + + u8ToU16(fwvers, fw_vers); + if (*fw_vers != 0) { + res = readConfig(ADDR_CONFIG_ID, confid, CONFIG_ID_BYTE); + if (res < OK) { + logError(1, + "%s getFirmwareVersion: unable to read config_id ERROR %08X\n", + tag, ERROR_FW_VER_READ); + return (res | ERROR_FW_VER_READ); + } + u8ToU16(confid, config_id); + } else { + *config_id = 0x0000; + } + + logError(0, "%s FW VERS = %04X\n", tag, *fw_vers); + logError(0, "%s CONFIG ID = %04X\n", tag, *config_id); + return OK; + +} + +/** +* Retrieve the actual FW data from the system (bin file or header file) +* @param pathToFile name of FW file to load or "NULL" if the FW data should be loaded by a .h file +* @param data pointer to the pointer which will contains the FW data +* @param size pointer to a variable which will contain the size of the loaded data +* @return OK if success or an error code which specify the type of error encountered +*/ +int getFWdata(const char *pathToFile, u8 **data, int *size) +{ + const struct firmware *fw = NULL; + struct device *dev = NULL; + int res, from = 0; + char *path = (char *)pathToFile; + + logError(1, "%s getFWdata starting ...\n", tag); + if (strncmp(pathToFile, "NULL", 4) == 0) { + from = 1; + path = (char *)fts_info->board->default_fw_name; + } + switch (from) { +#ifdef FW_H_FILE + case 1: + logError(1, "%s Read FW from .h file!\n", tag); + *size = FW_SIZE_NAME; + *data = (u8 *) kmalloc((*size) * sizeof(u8), GFP_KERNEL); + if (*data == NULL) { + logError(1, + "%s getFWdata: Impossible to allocate memory! ERROR %08X\n", + tag, ERROR_ALLOC); + return ERROR_ALLOC; + } + memcpy(*data, (u8 *) FW_ARRAY_NAME, (*size)); + + break; +#endif + default: + logError(1, "%s Read FW from BIN file %s !\n", tag, path); + dev = getDev(); + + if (dev != NULL) { + res = request_firmware(&fw, path, dev); + if (res == 0) { + *size = fw->size; + *data = + (u8 *) kmalloc((*size) * sizeof(u8), + GFP_KERNEL); + if (*data == NULL) { + logError(1, + "%s getFWdata: Impossible to allocate memory! ERROR %08X\n", + tag, ERROR_ALLOC); + release_firmware(fw); + return ERROR_ALLOC; + } + memcpy(*data, (u8 *) fw->data, (*size)); + release_firmware(fw); + } else { + logError(1, + "%s getFWdata: No File found! ERROR %08X\n", + tag, ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; + } + + } else { + logError(1, + "%s getFWdata: No device found! ERROR %08X\n", + tag, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + } + + logError(1, "%s getFWdata Finished!\n", tag); + return OK; + +} + +/** +* Perform all the steps to read the FW that should be burnt in the IC from the system and parse it in order to fill a Firmware struct with the relevant info +* @param path name of FW file to load or "NULL" if the FW data should be loaded by a .h file +* @param fw pointer to a Firmware variable which will contains the FW data and info +* @param keep_cx if 1, the CX area will be loaded otherwise will be skipped +* @return OK if success or an error code which specify the type of error encountered +*/ +int readFwFile(const char *path, Firmware *fw, int keep_cx) +{ + int res; + int orig_size; + u8 *orig_data = NULL; + + res = getFWdata(path, &orig_data, &orig_size); + if (res < OK) { + logError(1, + "%s readFwFile: impossible retrieve FW... ERROR %08X\n", + tag, ERROR_MEMH_READ); + return (res | ERROR_MEMH_READ); + } + res = parseBinFile(orig_data, orig_size, fw, keep_cx); + if (res < OK) { + logError(1, "%s readFwFile: impossible parse ERROR %08X\n", tag, + ERROR_MEMH_READ); + return (res | ERROR_MEMH_READ); + } + + return OK; + +} + +/** +* Perform all the steps necessary to burn the FW into the IC +* @param path name of FW file to load or "NULL" if the FW data should be loaded by a .h file +* @param force if 1, the flashing procedure will be forced and executed regardless the additional info, otherwise the FW in the file will be burnt only if it is newer than the one running in the IC +* @param keep_cx if 1, the CX area will be loaded and burnt otherwise will be skipped and the area will be untouched +* @return OK if success or an error code which specify the type of error encountered +*/ +int flashProcedure(const char *path, int force, int keep_cx) +{ + Firmware fw; + int res; + + fw.data = NULL; + logError(0, "%s Reading Fw file... \n", tag); + res = readFwFile(path, &fw, keep_cx); + if (res < OK) { + logError(1, "%s flashProcedure: ERROR %08X \n", tag, + (res | ERROR_FLASH_PROCEDURE)); + kfree(fw.data); + return (res | ERROR_FLASH_PROCEDURE); + } + logError(0, "%s Fw file read COMPLETED! \n", tag); + + logError(0, "%s Starting flashing procedure... \n", tag); + res = flash_burn(fw, force, keep_cx); + if (res < OK && res != (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED)) { + logError(1, "%s flashProcedure: ERROR %08X \n", tag, + ERROR_FLASH_PROCEDURE); + kfree(fw.data); + return (res | ERROR_FLASH_PROCEDURE); + } + logError(0, "%s flashing procedure Finished!\n", tag); + kfree(fw.data); + + return res; +} + + +/** +* Poll the Flash Status Registers after the execution of a command to check if the Flash becomes ready within a timeout +* @param type register to check according to the previous command sent +* @return OK if success or an error code which specify the type of error encountered +*/ +int wait_for_flash_ready(u8 type) +{ + + u8 cmd[5] = { FTS_CMD_HW_REG_R, 0x20, 0x00, 0x00, type }; + + u8 readData[2] = { 0 }; + int i, res = -1; + + logError(0, "%s Waiting for flash ready ... \n", tag); + for (i = 0; i < FLASH_RETRY_COUNT && res != 0; i++) { + res = fts_writeRead_dma_safe(cmd, ARRAY_SIZE(cmd), readData, 2); + if (res < OK) { + logError(1, "%s wait_for_flash_ready: ERROR % 08X\n", + tag, ERROR_BUS_W); + } else { +#ifdef I2C_INTERFACE + res = readData[0] & 0x80; +#else + res = readData[1] & 0x80; +#endif + + logError(0, "%s flash status = %d \n", tag, res); + } + mdelay(FLASH_WAIT_BEFORE_RETRY); + } + + if (i == FLASH_RETRY_COUNT && res != 0) { + logError(1, "%s Wait for flash TIMEOUT! ERROR %08X \n", tag, + ERROR_TIMEOUT); + return ERROR_TIMEOUT; + } + + logError(0, "%s Flash READY! \n", tag); + return OK; +} + +/** + * Put the M3 in hold + * @return OK if success or an error code which specify the type of error encountered + */ +int hold_m3(void) +{ + int ret; + u8 cmd[1] = { 0x01 }; + + logError(0, "%s Command m3 hold... \n", tag); + ret = + fts_writeU8UX(FTS_CMD_HW_REG_W, ADDR_SIZE_HW_REG, ADDR_SYSTEM_RESET, + cmd, 1); + if (ret < OK) { + logError(1, "%s hold_m3: ERROR %08X\n", tag, ret); + return ret; + } + logError(0, "%s Hold M3 DONE! \n", tag); + +#if !defined(I2C_INTERFACE) && defined(SPI4_WIRE) + logError(0, "%s Setting SPI4 mode... \n", tag); + cmd[0] = 0x10; + ret = + fts_writeU8UX(FTS_CMD_HW_REG_W, ADDR_SIZE_HW_REG, + ADDR_GPIO_DIRECTION, cmd, 1); + if (ret < OK) { + logError(1, "%s hold_m3: can not set gpio dir ERROR %08X\n", + tag, ret); + return ret; + } + + cmd[0] = 0x02; + ret = + fts_writeU8UX(FTS_CMD_HW_REG_W, ADDR_SIZE_HW_REG, ADDR_GPIO_PULLUP, + cmd, 1); + if (ret < OK) { + logError(1, "%s hold_m3: can not set gpio pull-up ERROR %08X\n", + tag, ret); + return ret; + } + + cmd[0] = 0x07; + ret = + fts_writeU8UX(FTS_CMD_HW_REG_W, ADDR_SIZE_HW_REG, + ADDR_GPIO_CONFIG_REG2, cmd, 1); + if (ret < OK) { + logError(1, "%s hold_m3: can not set gpio config ERROR %08X\n", + tag, ret); + return ret; + } + + cmd[0] = 0x30; + ret = + fts_writeU8UX(FTS_CMD_HW_REG_W, ADDR_SIZE_HW_REG, + ADDR_GPIO_CONFIG_REG0, cmd, 1); + if (ret < OK) { + logError(1, "%s hold_m3: can not set gpio config ERROR %08X\n", + tag, ret); + return ret; + } + + cmd[0] = SPI4_MASK; + ret = + fts_writeU8UX(FTS_CMD_HW_REG_W, ADDR_SIZE_HW_REG, ADDR_ICR, cmd, 1); + if (ret < OK) { + logError(1, "%s hold_m3: can not set spi4 mode ERROR %08X\n", + tag, ret); + return ret; + } + mdelay(1); +#endif + + return OK; +} + +/** +* Parse the raw data read from a FW file in order to fill properly the fields of a Firmware variable +* @param fw_data raw FW data loaded from system +* @param fw_size size of fw_data +* @param fwData pointer to a Firmware variable which will contain the processed data +* @param keep_cx if 1, the CX area will be loaded and burnt otherwise will be skipped and the area will be untouched +* @return OK if success or an error code which specify the type of error encountered +*/ +int parseBinFile(u8 *fw_data, int fw_size, Firmware *fwData, int keep_cx) +{ + + int dimension, index = 0; + u32 temp; + int res, i; + + if (fw_size < FW_HEADER_SIZE + FW_BYTES_ALLIGN || fw_data == NULL) { + logError(1, + "%s parseBinFile: Read only %d instead of %d... ERROR %08X\n", + tag, fw_size, FW_HEADER_SIZE + FW_BYTES_ALLIGN, + ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; + goto END; + } else { + u8ToU32(&fw_data[index], &temp); + if (temp != FW_HEADER_SIGNATURE) { + logError(1, + "%s parseBinFile: Wrong Signature %08X ... ERROR %08X\n", + tag, temp, ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; + goto END; + } + logError(0, "%s parseBinFile: Fw Signature OK!\n", tag); + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + if (temp != FW_FTB_VER) { + logError(1, + "%s parseBinFile: Wrong ftb_version %08X ... ERROR %08X\n", + tag, temp, ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; + goto END; + } + logError(0, "%s parseBinFile: ftb_version OK!\n", tag); + index += FW_BYTES_ALLIGN; + if (fw_data[index] != DCHIP_ID_0 + || fw_data[index + 1] != DCHIP_ID_1) { + logError(1, + "%s parseBinFile: Wrong target %02X != %02X %02X != %02X ... ERROR %08X\n", + tag, fw_data[index], DCHIP_ID_0, + fw_data[index + 1], DCHIP_ID_1, + ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; + goto END; + } + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + logError(1, "%s parseBinFile: FILE SVN REV = %08X\n", tag, + temp); + + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + fwData->fw_ver = temp; + logError(1, "%s parseBinFile: FILE Fw Version = %04X\n", tag, + fwData->fw_ver); + + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + fwData->config_id = temp; + logError(1, "%s parseBinFile: FILE Config Project ID = %08X\n", + tag, temp); + + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + logError(1, "%s parseBinFile: FILE Config Version = %08X\n", + tag, temp); + + index += FW_BYTES_ALLIGN * 2; + + index += FW_BYTES_ALLIGN; + logError(1, "%s parseBinFile: File External Release = ", tag); + for (i = 0; i < EXTERNAL_RELEASE_INFO_SIZE; i++) { + fwData->externalRelease[i] = fw_data[index++]; + logError(1, "%02X ", fwData->externalRelease[i]); + } + logError(1, "\n"); + + u8ToU32(&fw_data[index], &temp); + fwData->sec0_size = temp; + logError(1, "%s parseBinFile: sec0_size = %08X (%d bytes)\n", + tag, fwData->sec0_size, fwData->sec0_size); + + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + fwData->sec1_size = temp; + logError(1, "%s parseBinFile: sec1_size = %08X (%d bytes)\n", + tag, fwData->sec1_size, fwData->sec1_size); + + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + fwData->sec2_size = temp; + logError(1, "%s parseBinFile: sec2_size = %08X (%d bytes) \n", + tag, fwData->sec2_size, fwData->sec2_size); + + index += FW_BYTES_ALLIGN; + u8ToU32(&fw_data[index], &temp); + fwData->sec3_size = temp; + logError(1, "%s parseBinFile: sec3_size = %08X (%d bytes) \n", + tag, fwData->sec3_size, fwData->sec3_size); + + index += FW_BYTES_ALLIGN; + + dimension = + fwData->sec0_size + fwData->sec1_size + fwData->sec2_size + + fwData->sec3_size; + temp = fw_size; + + if (dimension + FW_HEADER_SIZE + FW_BYTES_ALLIGN != temp) { + logError(1, + "%s parseBinFile: Read only %d instead of %d... ERROR %08X\n", + tag, fw_size, + dimension + FW_HEADER_SIZE + FW_BYTES_ALLIGN, + ERROR_FILE_PARSE); + res = ERROR_FILE_PARSE; + goto END; + } + + fwData->data = + (u8 *) kmalloc(dimension * sizeof(u8), GFP_KERNEL); + if (fwData->data == NULL) { + logError(1, "%s parseBinFile: ERROR %08X\n", tag, + ERROR_ALLOC); + res = ERROR_ALLOC; + goto END; + } + + index += FW_BYTES_ALLIGN; + memcpy(fwData->data, &fw_data[index], dimension); + if (fwData->sec2_size != 0) { + u8ToU16(&fwData->data + [fwData->sec0_size + fwData->sec1_size + + FW_CX_VERSION], &fwData->cx_ver); + + } else { + logError(1, + "%s parseBinFile: Initialize cx_ver to default value! \n", + tag); + fwData->cx_ver = systemInfo.u16_cxVer; + } + + logError(1, "%s parseBinFile: CX Version = %04X \n", tag, + fwData->cx_ver); + + fwData->data_size = dimension; + + logError(0, "%s READ FW DONE %d bytes!\n", tag, + fwData->data_size); + res = OK; + goto END; + } + +END: + kfree(fw_data); + return res; +} + +/** + * Enable UVLO and Auto Power Down Mode + * @return OK if success or an error code which specify the type of error + */ +int flash_enable_uvlo_autopowerdown(void) +{ + u8 cmd[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_UVLO_ENABLE_CODE0, + FLASH_UVLO_ENABLE_CODE1 }; + u8 cmd1[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_AUTOPOWERDOWN_ENABLE_CODE0, + FLASH_AUTOPOWERDOWN_ENABLE_CODE1 }; + logError(0, "%s Command enable uvlo ...\n", tag); + if (fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)) < OK) { + logError(1, "%s flash_enable_uvlo_autopowerdown: ERROR %08X\n", tag, ERROR_BUS_W); + return ERROR_BUS_W; + } + if (fts_write_dma_safe(cmd1, ARRAY_SIZE(cmd1)) < OK) { + logError(1, "%s flash_enable_uvlo_autopowerdown: ERROR %08X\n", tag, ERROR_BUS_W); + return ERROR_BUS_W; + } + logError(0, "%s Enable uvlo and flash auto power down DONE!\n", tag); + return OK; +} +/** + * Unlock the flash to be programmed + * @return OK if success or an error code which specify the type of error + */ +int flash_unlock(void) +{ + + u8 cmd[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_UNLOCK_CODE0, + FLASH_UNLOCK_CODE1 }; + + u8 cmd1[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_UNLOCK_CODE2, + FLASH_UNLOCK_CODE3 }; + + logError(0, "%s Command unlock ...\n", tag); + if (fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)) < OK) { + logError(1, "%s flash_unlock: ERROR %08X\n", tag, ERROR_BUS_W); + return ERROR_BUS_W; + } + + if (fts_write_dma_safe(cmd1, ARRAY_SIZE(cmd1)) < OK) { + logError(1, "%s Command unlock: ERROR %08X\n", tag, ERROR_BUS_W); + return ERROR_BUS_W; + } + logError(0, "%s Unlock flash DONE!\n", tag); + + return OK; + +} + +/** +* Unlock the flash to be erased +* @return OK if success or an error code which specify the type of error encountered +*/ +int flash_erase_unlock(void) +{ + + u8 cmd[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_ERASE_UNLOCK_CODE0, + FLASH_ERASE_UNLOCK_CODE1 + }; + + logError(0, "%s Try to erase unlock flash... \n", tag); + + logError(0, "%s Command erase unlock ... \n", tag); + if (fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)) < 0) { + logError(1, "%s flash_erase_unlock: ERROR %08X\n", tag, + ERROR_BUS_W); + return ERROR_BUS_W; + } + + logError(0, "%s Erase Unlock flash DONE! \n", tag); + + return OK; + +} + +/** +* Erase the full flash +* @return OK if success or an error code which specify the type of error encountered +*/ +int flash_full_erase(void) +{ + int status; + + u8 cmd1[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_ERASE_CODE0 + 1, 0x00 }; + u8 cmd[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_ERASE_CODE0, + FLASH_ERASE_CODE1 + }; + + if (fts_write_dma_safe(cmd1, ARRAY_SIZE(cmd1)) < OK) { + logError(1, "%s flash_erase_page_by_page: ERROR %08X\n", tag, + ERROR_BUS_W); + return ERROR_BUS_W; + } + + logError(0, "%s Command full erase sent ... \n", tag); + if (fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)) < OK) { + logError(1, "%s flash_full_erase: ERROR %08X\n", tag, + ERROR_BUS_W); + return ERROR_BUS_W; + } + + status = wait_for_flash_ready(FLASH_ERASE_CODE0); + + if (status != OK) { + logError(1, "%s flash_full_erase: ERROR %08X\n", tag, + ERROR_FLASH_NOT_READY); + return (status | ERROR_FLASH_NOT_READY); + } + + logError(0, "%s Full Erase flash DONE! \n", tag); + + return OK; + +} + +/** +* Erase the flash page by page, giving the possibility to skip the CX area and maintain therefore its value +* @param keep_cx if SKIP_PANEL_INIT the Panel Init pages will be skipped, if > SKIP_PANEL_CX_INIT Cx and Panel Init pages otherwise all the pages will be deleted +* @return OK if success or an error code which specify the type of error encountered +*/ +int flash_erase_page_by_page(ErasePage keep_cx) +{ + + u8 status, i = 0; + u8 cmd1[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_ERASE_CODE0 + 1, 0x00 }; + u8 cmd[6] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x00, FLASH_ERASE_CODE0, 0xA0 }; + u8 cmd2[9] = { FTS_CMD_HW_REG_W, 0x20, 0x00, 0x01, 0x28, 0xFF, 0xFF, 0xFF, 0xFF }; + u8 mask[4] = { 0 }; + + for (i = FLASH_CX_PAGE_START; + i <= FLASH_CX_PAGE_END && keep_cx >= SKIP_PANEL_CX_INIT; i++) { + logError(0, "%s Skipping erase CX page %d! \n", tag, i); + fromIDtoMask(i, mask, 4); + } + + for (i = FLASH_PANEL_PAGE_START; + i <= FLASH_PANEL_PAGE_END && keep_cx >= SKIP_PANEL_INIT; i++) { + logError(0, "%s Skipping erase Panel Init page %d! \n", tag, i); + fromIDtoMask(i, mask, 4); + } + + logError(0, "%s Setting the page mask = ", tag, i); + for (i = 0; i < 4; i++) { + cmd2[5 + i] = cmd2[5 + i] & (~mask[i]); + logError(0, "%02X ", cmd2[5 + i]); + } + + logError(0, "\n%s Writing page mask... \n", tag); + if (fts_write_dma_safe(cmd2, ARRAY_SIZE(cmd2)) < OK) { + logError(1, + "%s flash_erase_page_by_page: Page mask ERROR %08X\n", + tag, ERROR_BUS_W); + return ERROR_BUS_W; + } + + if (fts_write_dma_safe(cmd1, ARRAY_SIZE(cmd1)) < OK) { + logError(1, + "%s flash_erase_page_by_page: Disable info ERROR %08X\n", + tag, ERROR_BUS_W); + return ERROR_BUS_W; + } + + logError(0, "%s Command erase pages sent ... \n", tag); + if (fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)) < OK) { + logError(1, "%s flash_erase_page_by_page: Erase ERROR %08X\n", + tag, ERROR_BUS_W); + return ERROR_BUS_W; + } + + status = wait_for_flash_ready(FLASH_ERASE_CODE0); + + if (status != OK) { + + logError(1, "%s flash_erase_page_by_page: ERROR % 08X\n", tag, + ERROR_FLASH_NOT_READY); + return (status | ERROR_FLASH_NOT_READY); + } + + logError(0, "%s Erase flash page by page DONE! \n", tag); + + return OK; +} + +/** +* Start the DMA procedure which actually transfer and burn the data loaded from memory into the Flash +* @return OK if success or an error code which specify the type of error encountered +*/ +int start_flash_dma(void) +{ + int status; + u8 cmd[12] = { FLASH_CMD_WRITE_REGISTER, 0x20, 0x00, 0x00, + 0x6B, 0x00, 0x40, 0x42, 0x0F, 0x00, 0x00, FLASH_DMA_CODE1 }; + + + logError(0, "%s Command flash DMA ... \n", tag); + if (fts_write_dma_safe(cmd, ARRAY_SIZE(cmd)) < OK) { + logError(1, "%s start_flash_dma: ERROR %08X\n", tag, + ERROR_BUS_W); + return ERROR_BUS_W; + } + + status = wait_for_flash_ready(FLASH_DMA_CODE0); + + if (status != OK) { + logError(1, "%s start_flash_dma: ERROR %08X\n", tag, + ERROR_FLASH_NOT_READY); + return (status | ERROR_FLASH_NOT_READY); + } + + logError(0, "%s flash DMA DONE! \n", tag); + + return OK; +} + +/** +* Copy the FW data that should be burnt in the Flash into the memory and then the DMA will take care about burning it into the Flash +* @param address address in memory where to copy the data, possible values are FLASH_ADDR_CODE, FLASH_ADDR_CONFIG, FLASH_ADDR_CX +* @param data pointer to an array of byte which contain the data that should be copied into the memory +* @param size size of data +* @return OK if success or an error code which specify the type of error encountered +*/ +int fillFlash(u32 address, u8 *data, int size) +{ + int remaining = size, index = 0; + int toWrite = 0; + int byteBlock = 0; + int wheel = 0; + u32 addr = 0; + int res; + int delta; + u8 *buff = NULL; + u8 buff2[12] = { 0 }; + + buff = (u8 *) kmalloc((DMA_CHUNK + 5) * sizeof(u8), GFP_KERNEL); + if (buff == NULL) { + logError(1, "%s fillFlash: ERROR %08X\n", tag, ERROR_ALLOC); + return ERROR_ALLOC; + } + + while (remaining > 0) { + byteBlock = 0; + + addr = 0x00100000; + + while (byteBlock < FLASH_CHUNK && remaining > 0) { + index = 0; + if (remaining >= DMA_CHUNK) { + if ((byteBlock + DMA_CHUNK) <= FLASH_CHUNK) { + toWrite = DMA_CHUNK; + remaining -= DMA_CHUNK; + byteBlock += DMA_CHUNK; + } else { + delta = FLASH_CHUNK - byteBlock; + toWrite = delta; + remaining -= delta; + byteBlock += delta; + } + } else { + if ((byteBlock + remaining) <= FLASH_CHUNK) { + toWrite = remaining; + byteBlock += remaining; + remaining = 0; + + } else { + delta = FLASH_CHUNK - byteBlock; + toWrite = delta; + remaining -= delta; + byteBlock += delta; + } + } + + buff[index++] = FTS_CMD_HW_REG_W; + buff[index++] = (u8) ((addr & 0xFF000000) >> 24); + buff[index++] = (u8) ((addr & 0x00FF0000) >> 16); + buff[index++] = (u8) ((addr & 0x0000FF00) >> 8); + buff[index++] = (u8) (addr & 0x000000FF); + + memcpy(&buff[index], data, toWrite); + if (fts_write_dma_safe(buff, index + toWrite) < OK) { + logError(1, "%s fillFlash: ERROR %08X\n", tag, + ERROR_BUS_W); + kfree(buff); + return ERROR_BUS_W; + } + addr += toWrite; + data += toWrite; + } + + byteBlock = byteBlock / 4 - 1; + index = 0; + + buff2[index++] = FLASH_CMD_WRITE_REGISTER; + buff2[index++] = 0x20; + buff2[index++] = 0x00; + buff2[index++] = 0x00; + buff2[index++] = FLASH_DMA_CONFIG; + buff2[index++] = 0x00; + buff2[index++] = 0x00; + + addr = address + ((wheel * FLASH_CHUNK) / 4); + buff2[index++] = (u8) ((addr & 0x000000FF)); + buff2[index++] = (u8) ((addr & 0x0000FF00) >> 8); + buff2[index++] = (u8) (byteBlock & 0x000000FF); + buff2[index++] = (u8) ((byteBlock & 0x0000FF00) >> 8); + buff2[index++] = 0x00; + + logError(0, + "%s DMA Command = %02X , address = %02X %02X, words = %02X %02X \n", + tag, buff2[0], buff2[8], buff2[7], buff2[10], + buff2[9]); + + if (fts_write_dma_safe(buff2, index) < OK) { + logError(1, + "%s Error during filling Flash! ERROR %08X \n", + tag, ERROR_BUS_W); + kfree(buff); + return ERROR_BUS_W; + } + + res = start_flash_dma(); + if (res < OK) { + logError(1, + "%s Error during flashing DMA! ERROR %08X \n", + tag, res); + kfree(buff); + return res; + } + wheel++; + } + kfree(buff); + return OK; +} + +/** +* Execute the procedure to burn a FW in FTM4/FTI IC +* @param fw structure which contain the FW to be burnt +* @param force_burn if >0, the flashing procedure will be forced and executed regardless the additional info, otherwise the FW in the file will be burnt only if it is newer than the one running in the IC +* @param keep_cx if 1, the function preserve the CX/Panel Init area otherwise will be cleared +* @return OK if success or an error code which specify the type of error encountered +*/ +int flash_burn(Firmware fw, int force_burn, int keep_cx) +{ + int res; + + if (!force_burn) { + if (systemInfo.u16_fwVer != fw.fw_ver) + goto start; + for (res = EXTERNAL_RELEASE_INFO_SIZE - 1; res >= 0; res--) { + if (fw.externalRelease[res] != + systemInfo.u8_releaseInfo[res]) + goto start; + } + logError(1, + "%s flash_burn: Firmware in the chip newer or equal to the one to burn! NO UPDATE ERROR %08X \n", + tag, ERROR_FW_NO_UPDATE); + return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED); + } else { + if (force_burn == CRC_CX && fw.sec2_size == 0) { + for (res = EXTERNAL_RELEASE_INFO_SIZE - 1; res >= 0; + res--) { + if (fw.externalRelease[res] > + systemInfo.u8_releaseInfo[res]) + force_burn = 0; + goto start; + } + logError(1, + "%s flash_burn: CRC in CX but fw does not contain CX data! NO UPDATE ERROR %08X \n", + tag, ERROR_FW_NO_UPDATE); + return (ERROR_FW_NO_UPDATE | ERROR_FLASH_BURN_FAILED); + } + } + +start: + logError(0, "%s Programming Procedure for flashing started: \n\n", tag); + + logError(0, "%s 1) SYSTEM RESET: \n", tag); + res = fts_system_reset(); + if (res < 0) { + logError(1, "%s system reset FAILED!\n", tag); + if (res != (ERROR_SYSTEM_RESET_FAIL | ERROR_TIMEOUT)) + return (res | ERROR_FLASH_BURN_FAILED); + } else + logError(0, "%s system reset COMPLETED!\n\n", tag); + msleep(30); /* required by hw during flash procedure */ + logError(0, "%s 2) HOLD M3 : \n", tag); + res = hold_m3(); + if (res < OK) { + logError(1, "%s hold_m3 FAILED!\n", tag); + return (res | ERROR_FLASH_BURN_FAILED); + } else + logError(0, "%s hold_m3 COMPLETED!\n\n", tag); + + logError(0, "%s 3) ENABLE UVLO AND AUTO POWER DOWN MODE :\n", tag); + res = flash_enable_uvlo_autopowerdown(); + if (res < OK) { + logError(1, "%s flash_enable_uvlo_autopowerdown FAILED!\n", tag); + return res | ERROR_FLASH_BURN_FAILED; + } else + logError(0, "%s flash_enable_uvlo_autopowerdown COMPLETED!\n\n", tag); + logError(0, "%s 4) FLASH UNLOCK: \n", tag); + res = flash_unlock(); + if (res < OK) { + logError(1, "%s flash unlock FAILED! ERROR %08X\n", tag, + ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } else { + logError(0, "%s flash unlock COMPLETED!\n\n", tag); + } + + logError(0, "%s 5) FLASH ERASE UNLOCK: \n", tag); + res = flash_erase_unlock(); + if (res < 0) { + logError(1, "%s flash unlock FAILED! ERROR %08X\n", tag, + ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } else { + logError(0, "%s flash unlock COMPLETED!\n\n", tag); + } + + logError(0, "%s 6) FLASH ERASE: \n", tag); + if (keep_cx > 0) { + if (fw.sec2_size != 0 && force_burn == CRC_CX) + res = flash_erase_page_by_page(SKIP_PANEL_INIT); + else + res = flash_erase_page_by_page(SKIP_PANEL_CX_INIT); + } else { + res = flash_erase_page_by_page(SKIP_PANEL_INIT); + if (fw.sec2_size == 0) + logError(1, + "%s WARNING!!! Erasing CX memory but no CX in fw file! touch will not work right after fw update! \n", + tag); + } + + if (res < OK) { + logError(1, "%s flash erase FAILED! ERROR %08X\n", tag, + ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } else { + logError(0, "%s flash erase COMPLETED!\n\n", tag); + } + + logError(0, "%s 7) LOAD PROGRAM: \n", tag); + res = fillFlash(FLASH_ADDR_CODE, &fw.data[0], fw.sec0_size); + if (res < OK) { + logError(1, "%s load program ERROR %08X\n", tag, + ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } + logError(1, "%s load program DONE!\n", tag); + + logError(0, "%s 8) LOAD CONFIG: \n", tag); + res = + fillFlash(FLASH_ADDR_CONFIG, &(fw.data[fw.sec0_size]), + fw.sec1_size); + if (res < OK) { + logError(1, "%s load config ERROR %08X\n", tag, + ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } + logError(1, "%s load config DONE!\n", tag); + + if (fw.sec2_size != 0) { + if ((force_burn == CRC_CX) || (keep_cx <= 0)) { + logError(0, "%s 8.1) LOAD CX: \n", tag); + res = + fillFlash(FLASH_ADDR_CX, + &(fw.data[fw.sec0_size + fw.sec1_size]), + fw.sec2_size); + if (res < OK) { + logError(1, "%s load cx ERROR %08X\n", tag, + ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } + logError(1, "%s load cx DONE!\n", tag); + } + } + + logError(0, "%s Flash burn COMPLETED!\n\n", tag); + + logError(0, "%s 9) SYSTEM RESET: \n", tag); + res = fts_system_reset(); + if (res < 0) { + logError(1, "%s system reset FAILED! ERROR %08X\n", tag, + ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } + logError(0, "%s system reset COMPLETED!\n\n", tag); + + logError(0, "%s 10) FINAL CHECK: \n", tag); + res = readSysInfo(0); + if (res < 0) { + logError(1, + "%s flash_burn: Unable to retrieve Chip INFO! ERROR %08X\n", + tag, ERROR_FLASH_BURN_FAILED); + return (res | ERROR_FLASH_BURN_FAILED); + } + + for (res = 0; res < EXTERNAL_RELEASE_INFO_SIZE; res++) { + if (fw.externalRelease[res] != systemInfo.u8_releaseInfo[res]) { + logError(1, + "%s Firmware in the chip different from the one that was burn! \n", + tag); + return ERROR_FLASH_BURN_FAILED; + } + } + + logError(0, "%s Final check OK! \n", tag); + + return OK; +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsFlash.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsFlash.h new file mode 100644 index 000000000000..5a4c19221228 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsFlash.h @@ -0,0 +1,100 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS API for Flashing the IC * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsFlash.h +* \brief Contains all the definitions and structs to handle the FW update process +*/ + +#ifndef FTS_FLASH_H +#define FTS_FLASH_H + +#include "ftsSoftware.h" + +/*Flash possible status*/ +#define FLASH_READY 0 /*value to indicate that the flash is ready*/ +#define FLASH_BUSY 1 /*value to indicate that the flash is busy*/ +#define FLASH_UNKNOWN -1 /*value to indicate an unknown status of the flash*/ + +#define FLASH_STATUS_BYTES 1 /*number of bytes to check for read the flash status*/ + +/*Flash timing parameters*/ +#define FLASH_RETRY_COUNT 200 /*number of attemps to read the flash status*/ +#define FLASH_WAIT_BEFORE_RETRY 50 /*time to wait in ms between one status reading and another*/ + +#ifdef FW_H_FILE +#define PATH_FILE_FW "NULL" +#else +#define PATH_FILE_FW "st_fts.ftb" /*new FW bin file name*/ +#endif + +#define FLASH_CHUNK (64 * 1024) /*Max number of bytes that the DMA can burn on the flash in one shot in FTI*/ +#define DMA_CHUNK 32 /*Max number of bytes that can be written in I2C to the DMA*/ + +/** + * Define which kind of erase page by page should be performed + */ +typedef enum { + ERASE_ALL = 0, /*erase all the pages*/ + SKIP_PANEL_INIT = 1, /*skip erase Panel Init Pages*/ + SKIP_PANEL_CX_INIT = 2 /*skip erase Panel Init and CX Pages*/ +} ErasePage; + +/** @addtogroup fw_file + * @{ + */ + +/** +* Struct which contains information and data of the FW that should be burnt into the IC +*/ +typedef struct { + u8 *data; /*pointer to an array of bytes which represent the FW data*/ + u16 fw_ver; /*FW version of the FW file*/ + u16 config_id; /*Config ID of the FW file*/ + u16 cx_ver; /*Cx version of the FW file*/ + u8 externalRelease[EXTERNAL_RELEASE_INFO_SIZE]; /*External Release Info of the FW file*/ + int data_size; /*dimension of data (the actual data to be burnt)*/ + u32 sec0_size; /*dimension of section 0 (FW) in .ftb file*/ + u32 sec1_size; /*dimension of section 1 (Config) in .ftb file*/ + u32 sec2_size; /*dimension of section 2 (Cx) in .ftb file*/ + u32 sec3_size; /*dimension of section 3 (TBD) in .ftb file*/ + +} Firmware; + +/** @}*/ + +/** @addtogroup flash_command + * @{ + */ + +int wait_for_flash_ready(u8 type); +int hold_m3(void); +int flash_erase_unlock(void); +int flash_full_erase(void); +int flash_erase_page_by_page(ErasePage keep_cx); +int start_flash_dma(void); +int fillFlash(u32 address, u8 *data, int size); + +int flash_unlock(void); +int getFirmwareVersion(u16 *fw_vers, u16 *config_id); +int getFWdata(const char *pathToFile, u8 **data, int *size); +int parseBinFile(u8 *fw_data, int fw_size, Firmware *fw, int keep_cx); +int readFwFile(const char *path, Firmware *fw, int keep_cx); +int flash_burn(Firmware fw, int force_burn, int keep_cx); +int flashProcedure(const char *path, int force, int keep_cx); +int flash_enable_uvlo_autopowerdown(void); +#endif + +/** @}*/ diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsFrame.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsFrame.c new file mode 100644 index 000000000000..3f2e7bf484ce --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsFrame.c @@ -0,0 +1,398 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS functions for getting frames * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsFrame.c +* \brief Contains all the functions to work with frames +*/ + +#include "ftsCompensation.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsFrame.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTool.h" +#include "ftsTime.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern SysInfo systemInfo; + +/** + * Read the channels lengths from the config memory + * @return OK if success or an error code which specify the type of error encountered + */ +int getChannelsLength(void) +{ + int ret; + u8 data[2]; + + if (data == NULL) { + logError(1, "%s getChannelsLength: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + ret = readConfig(ADDR_CONFIG_SENSE_LEN, data, 2); + if (ret < OK) { + logError(1, "%s getChannelsLength: ERROR %08X\n", tag, ret); + + return ret; + } + + systemInfo.u8_scrRxLen = (int)data[0]; + systemInfo.u8_scrTxLen = (int)data[1]; + + logError(0, "%s Force_len = %d Sense_Len = %d \n", tag, + systemInfo.u8_scrTxLen, systemInfo.u8_scrRxLen); + + return OK; +} + +/** +* Read and pack the frame data related to the nodes +* @param address address in memory when the frame data node start +* @param size amount of data to read +* @param frame pointer to an array of bytes which will contain the frame node data +* @return OK if success or an error code which specify the type of error encountered +*/ +int getFrameData(u16 address, int size, short *frame) +{ + int i, j, ret; + u8 *data = (u8 *) kmalloc(size * sizeof(u8), GFP_KERNEL); + if (data == NULL) { + logError(1, "%s getFrameData: ERROR %08X\n", tag, ERROR_ALLOC); + return ERROR_ALLOC; + } + + ret = + fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, data, + size, DUMMY_FRAMEBUFFER); + if (ret < OK) { + logError(1, "%s getFrameData: ERROR %08X\n", tag, ERROR_BUS_R); + kfree(data); + return ERROR_BUS_R; + } + j = 0; + for (i = 0; i < size; i += 2) { + frame[j] = (short)((data[i + 1] << 8) + data[i]); + j++; + } + kfree(data); + return OK; +} + +/** + * Return the number of Sense Channels (Rx) + * @return number of Rx channels + */ +int getSenseLen(void) +{ + if (systemInfo.u8_scrRxLen == 0) { + getChannelsLength(); + } + return systemInfo.u8_scrRxLen; +} + +/** + * Return the number of Force Channels (Tx) + * @return number of Tx channels + */ +int getForceLen(void) +{ + if (systemInfo.u8_scrTxLen == 0) { + getChannelsLength(); + } + return systemInfo.u8_scrTxLen; +} + +/******************** New API **************************/ + +/** +* Read a MS Frame from frame buffer memory +* @param type type of MS frame to read +* @param frame pointer to MutualSenseFrame variable which will contain the data +* @return OK if success or an error code which specify the type of error encountered +*/ +int getMSFrame3(MSFrameType type, MutualSenseFrame *frame) +{ + u16 offset; + int ret, force_len, sense_len; + + force_len = getForceLen(); + sense_len = getSenseLen(); + + frame->node_data = NULL; + + logError(0, "%s %s: Starting to get frame %02X \n", tag, __func__, + type); + switch (type) { + case MS_RAW: + offset = systemInfo.u16_msTchRawAddr; + goto LOAD_NORM; + case MS_FILTER: + offset = systemInfo.u16_msTchFilterAddr; + + goto LOAD_NORM; + case MS_STRENGTH: + offset = systemInfo.u16_msTchStrenAddr; + goto LOAD_NORM; + case MS_BASELINE: + offset = systemInfo.u16_msTchBaselineAddr; +LOAD_NORM: + if (force_len == 0 || sense_len == 0) { + logError(1, + "%s %s: number of channels not initialized ERROR %08X\n", + tag, __func__, ERROR_CH_LEN); + return (ERROR_CH_LEN | ERROR_GET_FRAME); + } + + break; + + case MS_KEY_RAW: + offset = systemInfo.u16_keyRawAddr; + goto LOAD_KEY; + case MS_KEY_FILTER: + offset = systemInfo.u16_keyFilterAddr; + goto LOAD_KEY; + case MS_KEY_STRENGTH: + offset = systemInfo.u16_keyStrenAddr; + goto LOAD_KEY; + case MS_KEY_BASELINE: + offset = systemInfo.u16_keyBaselineAddr; +LOAD_KEY: + if (systemInfo.u8_keyLen == 0) { + logError(1, + "%s %s: number of channels not initialized ERROR %08X\n", + tag, __func__, ERROR_CH_LEN); + return (ERROR_CH_LEN | ERROR_GET_FRAME); + } + force_len = 1; + sense_len = systemInfo.u8_keyLen; + break; + + case FRC_RAW: + offset = systemInfo.u16_frcRawAddr; + goto LOAD_FRC; + case FRC_FILTER: + offset = systemInfo.u16_frcFilterAddr; + goto LOAD_FRC; + case FRC_STRENGTH: + offset = systemInfo.u16_frcStrenAddr; + goto LOAD_FRC; + case FRC_BASELINE: + offset = systemInfo.u16_frcBaselineAddr; +LOAD_FRC: + if (force_len == 0) { + logError(1, + "%s %s: number of channels not initialized ERROR %08X\n", + tag, __func__, ERROR_CH_LEN); + return (ERROR_CH_LEN | ERROR_GET_FRAME); + } + sense_len = 1; + break; + default: + logError(1, "%s %s: Invalid type ERROR %08X\n", tag, __func__, + ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME); + return ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME; + } + + frame->node_data_size = ((force_len) * sense_len); + frame->header.force_node = force_len; + frame->header.sense_node = sense_len; + frame->header.type = type; + + logError(0, "%s %s: Force_len = %d Sense_len = %d Offset = %04X \n", + tag, __func__, force_len, sense_len, offset); + + frame->node_data = + (short *)kmalloc(frame->node_data_size * sizeof(short), GFP_KERNEL); + if (frame->node_data == NULL) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_ALLOC | ERROR_GET_FRAME); + return ERROR_ALLOC | ERROR_GET_FRAME; + } + + ret = + getFrameData(offset, frame->node_data_size * BYTES_PER_NODE, + (frame->node_data)); + if (ret < OK) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, + ERROR_GET_FRAME_DATA); + kfree(frame->node_data); + frame->node_data = NULL; + return (ret | ERROR_GET_FRAME_DATA | ERROR_GET_FRAME); + } + logError(0, "%s Frame acquired! \n", tag); + return frame->node_data_size; + +} + +/** +* Read a SS Frame from frame buffer +* @param type type of SS frame to read +* @param frame pointer to SelfSenseFrame variable which will contain the data +* @return OK if success or an error code which specify the type of error encountered +*/ +int getSSFrame3(SSFrameType type, SelfSenseFrame *frame) +{ + u16 offset_force, offset_sense; + int ret; + + frame->force_data = NULL; + frame->sense_data = NULL; + + frame->header.force_node = getForceLen(); + frame->header.sense_node = getSenseLen(); + + if (frame->header.force_node == 0 || frame->header.sense_node == 0) { + logError(1, + "%s %s: number of channels not initialized ERROR %08X\n", + tag, __func__, ERROR_CH_LEN); + return (ERROR_CH_LEN | ERROR_GET_FRAME); + } + + logError(0, "%s %s: Starting to get frame %02X \n", tag, __func__, + type); + switch (type) { + case SS_RAW: + offset_force = systemInfo.u16_ssTchTxRawAddr; + offset_sense = systemInfo.u16_ssTchRxRawAddr; + break; + case SS_FILTER: + offset_force = systemInfo.u16_ssTchTxFilterAddr; + offset_sense = systemInfo.u16_ssTchRxFilterAddr; + break; + case SS_STRENGTH: + offset_force = systemInfo.u16_ssTchTxStrenAddr; + offset_sense = systemInfo.u16_ssTchRxStrenAddr; + break; + case SS_BASELINE: + offset_force = systemInfo.u16_ssTchTxBaselineAddr; + offset_sense = systemInfo.u16_ssTchRxBaselineAddr; + break; + + case SS_HVR_RAW: + offset_force = systemInfo.u16_ssHvrTxRawAddr; + offset_sense = systemInfo.u16_ssHvrRxRawAddr; + break; + case SS_HVR_FILTER: + offset_force = systemInfo.u16_ssHvrTxFilterAddr; + offset_sense = systemInfo.u16_ssHvrRxFilterAddr; + break; + case SS_HVR_STRENGTH: + offset_force = systemInfo.u16_ssHvrTxStrenAddr; + offset_sense = systemInfo.u16_ssHvrRxStrenAddr; + break; + case SS_HVR_BASELINE: + offset_force = systemInfo.u16_ssHvrTxBaselineAddr; + offset_sense = systemInfo.u16_ssHvrRxBaselineAddr; + break; + + case SS_PRX_RAW: + offset_force = systemInfo.u16_ssPrxTxRawAddr; + offset_sense = systemInfo.u16_ssPrxRxRawAddr; + break; + case SS_PRX_FILTER: + offset_force = systemInfo.u16_ssPrxTxFilterAddr; + offset_sense = systemInfo.u16_ssPrxRxFilterAddr; + break; + case SS_PRX_STRENGTH: + offset_force = systemInfo.u16_ssPrxTxStrenAddr; + offset_sense = systemInfo.u16_ssPrxRxStrenAddr; + break; + case SS_PRX_BASELINE: + offset_force = systemInfo.u16_ssPrxTxBaselineAddr; + offset_sense = systemInfo.u16_ssPrxRxBaselineAddr; + break; + + default: + logError(1, "%s %s: Invalid type ERROR %08X\n", tag, __func__, + ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME); + return ERROR_OP_NOT_ALLOW | ERROR_GET_FRAME; + } + + frame->header.type = type; + + logError(0, + "%s %s: Force_len = %d Sense_len = %d Offset_force = %04X Offset_sense = %04X \n", + tag, __func__, frame->header.force_node, + frame->header.sense_node, offset_force, offset_sense); + + frame->force_data = + (short *)kmalloc(frame->header.force_node * sizeof(short), + GFP_KERNEL); + if (frame->force_data == NULL) { + logError(1, "%s %s: can not allocate force_data ERROR %08X\n", + tag, __func__, ERROR_ALLOC | ERROR_GET_FRAME); + return ERROR_ALLOC | ERROR_GET_FRAME; + } + + frame->sense_data = + (short *)kmalloc(frame->header.sense_node * sizeof(short), + GFP_KERNEL); + if (frame->sense_data == NULL) { + kfree(frame->force_data); + frame->force_data = NULL; + logError(1, "%s %s: can not allocate sense_data ERROR %08X\n", + tag, __func__, ERROR_ALLOC | ERROR_GET_FRAME); + return ERROR_ALLOC | ERROR_GET_FRAME; + } + + ret = + getFrameData(offset_force, + frame->header.force_node * BYTES_PER_NODE, + (frame->force_data)); + if (ret < OK) { + logError(1, + "%s %s: error while reading force data ERROR %08X\n", + tag, __func__, ERROR_GET_FRAME_DATA); + kfree(frame->force_data); + frame->force_data = NULL; + kfree(frame->sense_data); + frame->sense_data = NULL; + return (ret | ERROR_GET_FRAME_DATA | ERROR_GET_FRAME); + } + + ret = + getFrameData(offset_sense, + frame->header.sense_node * BYTES_PER_NODE, + (frame->sense_data)); + if (ret < OK) { + logError(1, + "%s %s: error while reading sense data ERROR %08X\n", + tag, __func__, ERROR_GET_FRAME_DATA); + kfree(frame->force_data); + frame->force_data = NULL; + kfree(frame->sense_data); + frame->sense_data = NULL; + return (ret | ERROR_GET_FRAME_DATA | ERROR_GET_FRAME); + } + + logError(0, "%s Frame acquired! \n", tag); + return frame->header.force_node + frame->header.sense_node; + +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsFrame.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsFrame.h new file mode 100644 index 000000000000..94bf412d1793 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsFrame.h @@ -0,0 +1,91 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS functions for getting frames * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsFrame.h +* \brief Contains all the definitions and structs to work with frames +*/ + +#ifndef FTS_FRAME_H +#define FTS_FRAME_H + +#include "ftsSoftware.h" + +/*Number of data bytes for each node */ +#define BYTES_PER_NODE 2 /*number of data bytes for each node*/ + +#define RETRY_FRAME_DATA_READ 2 /*max number of attempts to read a frame*/ + +/** +* Possible types of MS frames +*/ +typedef enum{ + MS_RAW = 0, /*Mutual Sense Raw Frame*/ + MS_FILTER = 1, /*Mutual Sense Filtered Frame*/ + MS_STRENGTH = 2, /*Mutual Sense Strength Frame (Baseline-Raw)*/ + MS_BASELINE = 3, /*Mutual Sense Baseline Frame*/ + MS_KEY_RAW = 4, /*Mutual Sense Key Raw Frame*/ + MS_KEY_FILTER = 5, /*Mutual Sense Key Filter Frame*/ + MS_KEY_STRENGTH = 6, /*Mutual Sense Key Strength Frame (Baseline-Raw)*/ + MS_KEY_BASELINE = 7, /*Mutual Sense Key Baseline Frame*/ + FRC_RAW = 8, /*Force Raw Frame*/ + FRC_FILTER = 9, /*Force Filtered Frame*/ + FRC_STRENGTH = 10, /*Force Strength Frame (Baseline-Raw)*/ + FRC_BASELINE = 11 /*Force Baseline Frame*/ +} MSFrameType; + +/** +* Possible types of SS frames +*/ +typedef enum{ + SS_RAW = 0, /*Self Sense Raw Frame*/ + SS_FILTER = 1, /*Self Sense Filtered Frame*/ + SS_STRENGTH = 2, /*Self Sense Strength Frame (Baseline-Raw)*/ + SS_BASELINE = 3, /*Self Sense Baseline Frame*/ + SS_HVR_RAW = 4, /*Self Sense Hover Raw Frame*/ + SS_HVR_FILTER = 5, /*Self Sense Hover Filter Frame*/ + SS_HVR_STRENGTH = 6, /*Self Sense Hover Strength Frame (Baseline-Raw)*/ + SS_HVR_BASELINE = 7, /*Self Sense Hover Baseline Frame*/ + SS_PRX_RAW = 8, /*Self Sense Proximity Raw Frame*/ + SS_PRX_FILTER = 9, /*Self Sense Proximity Filtered Frame*/ + SS_PRX_STRENGTH = 10, /*Self Sense Proximity Strength Frame (Baseline-Raw)*/ + SS_PRX_BASELINE = 11 /*Self Sense Proximity Baseline Frame*/ +} SSFrameType; + +/** +* Struct which contains the data of a MS Frame +*/ +typedef struct { + DataHeader header; /*Header which contain basic info of the frame*/ + short *node_data; /*Data of the frame*/ + int node_data_size; /*Dimension of the data of the frame*/ +} MutualSenseFrame; + +/** +* Struct which contains the data of a SS Frame +*/ +typedef struct { + DataHeader header; /*Header which contain basic info of the frame*/ + short *force_data; /*Force Channels Data*/ + short *sense_data; /*Sense Channels Data*/ +} SelfSenseFrame; + +int getChannelsLength(void); +int getFrameData(u16 address, int size, short *frame); +int getSenseLen(void); +int getForceLen(void); +int getMSFrame3(MSFrameType type, MutualSenseFrame *frame); +int getSSFrame3(SSFrameType type, SelfSenseFrame *frame); +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsGesture.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsGesture.c new file mode 100644 index 000000000000..3a4e2a66bf9e --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsGesture.c @@ -0,0 +1,349 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS Gesture Utilities * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsGesture.c +* \brief Contains all the functions and variable to handle the Gesture Detection features +*/ + +#include "ftsSoftware.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsGesture.h" +#include "ftsIO.h" +#include "ftsTime.h" +#include "ftsTool.h" + +static u8 gesture_mask[GESTURE_MASK_SIZE] = { 0 }; +u16 gesture_coordinates_x[GESTURE_MAX_COORDS_PAIRS_REPORT] = { 0 }; +u16 gesture_coordinates_y[GESTURE_MAX_COORDS_PAIRS_REPORT] = { 0 }; +int gesture_coords_reported = ERROR_OP_NOT_ALLOW; +static u8 refreshGestureMask; +struct mutex gestureMask_mutex; + +/** + * Update the gesture mask stored in the driver and have to be used in gesture mode + * @param mask pointer to a byte array which store the gesture mask update that want to be performed. + * @param size dimension in byte of mask. This size can be <= GESTURE_MASK_SIZE. If size < GESTURE_MASK_SIZE the bytes of mask are considering continuos and starting from the less significant byte. + * @param en 0 = enable the gestures set in mask, 1 = disable the gestures set in mask + * @return OK if success or an error code which specify the type of error encountered + */ +int updateGestureMask(u8 *mask, int size, int en) +{ + u8 temp; + int i; + + if (mask != NULL) { + if (size <= GESTURE_MASK_SIZE) { + if (en == FEAT_ENABLE) { + mutex_lock(&gestureMask_mutex); + logError(0, + "%s updateGestureMask: setting gesture mask to enable...\n", + tag); + if (mask != NULL) { + for (i = 0; i < size; i++) { + gesture_mask[i] = gesture_mask[i] | mask[i]; + } + } + refreshGestureMask = 1; + logError(0, + "%s updateGestureMask: gesture mask to enable SET! \n", + tag); + mutex_unlock(&gestureMask_mutex); + return OK; + } + + else if (en == FEAT_DISABLE) { + mutex_lock(&gestureMask_mutex); + logError(0, + "%s updateGestureMask: setting gesture mask to disable...\n", + tag); + for (i = 0; i < size; i++) { + temp = gesture_mask[i] ^ mask[i]; + gesture_mask[i] = + temp & gesture_mask[i]; + } + logError(0, + "%s updateGestureMask: gesture mask to disable SET! \n", + tag); + refreshGestureMask = 1; + mutex_unlock(&gestureMask_mutex); + return OK; + } else { + logError(1, + "updateGestureMask: Enable parameter Invalid! %d != %d or %d ERROR %08X", + tag, FEAT_DISABLE, FEAT_ENABLE, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + } else { + logError(1, + "%s updateGestureMask: Size not valid! %d > %d ERROR %08X \n", + tag, size, GESTURE_MASK_SIZE); + return ERROR_OP_NOT_ALLOW; + } + } else { + logError(1, "%s updateGestureMask: Mask NULL! ERROR %08X \n", + tag, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + +} + +/** + * Enable in the FW the gesture mask to be used in gesture mode + * @param mask pointer to a byte array which store the gesture mask update that want to be sent to the FW, if NULL, will be used gesture_mask set previously without any changes. + * @param size dimension in byte of mask. This size can be <= GESTURE_MASK_SIZE. If size < GESTURE_MASK_SIZE the bytes of mask are considering continuos and starting from the less significant byte. + * @return OK if success or an error code which specify the type of error encountered + */ +int enableGesture(u8 *mask, int size) +{ + int i, res; + + logError(0, "%s Trying to enable gesture... \n", tag); + + if (size <= GESTURE_MASK_SIZE) { + mutex_lock(&gestureMask_mutex); + if (mask != NULL) { + for (i = 0; i < size; i++) { + gesture_mask[i] = gesture_mask[i] | mask[i]; + } + } + + res = + setFeatures(FEAT_SEL_GESTURE, gesture_mask, + GESTURE_MASK_SIZE); + if (res < OK) { + logError(1, "%s enableGesture: ERROR %08X \n", tag, + res); + goto END; + } + + logError(0, "%s enableGesture DONE! \n", tag); + res = OK; + +END: + mutex_unlock(&gestureMask_mutex); + return res; + } else { + logError(1, + "%s enableGesture: Size not valid! %d > %d ERROR %08X \n", + tag, size, GESTURE_MASK_SIZE); + return ERROR_OP_NOT_ALLOW; + } + +} + +/** + * Disable in the FW the gesture mask to be used in gesture mode + * @param mask pointer to a byte array which store the gesture mask update that want to be sent to the FW, if NULL, all the gestures will be disabled. + * @param size dimension in byte of mask. This size can be <= GESTURE_MASK_SIZE. If size < GESTURE_MASK_SIZE the bytes of mask are considering continuos and starting from the less significant byte. + * @return OK if success or an error code which specify the type of error encountered + */ +int disableGesture(u8 *mask, int size) +{ + u8 temp; + int i, res; + u8 *pointer; + + logError(0, "%s Trying to disable gesture... \n", tag); + + if (size <= GESTURE_MASK_SIZE) { + mutex_lock(&gestureMask_mutex); + if (mask != NULL) { + for (i = 0; i < size; i++) { + + temp = gesture_mask[i] ^ mask[i]; + gesture_mask[i] = temp & gesture_mask[i]; + } + + pointer = gesture_mask; + } else { + i = 0; + pointer = (u8 *)&i; + } + + res = setFeatures(FEAT_SEL_GESTURE, pointer, GESTURE_MASK_SIZE); + if (res < OK) { + logError(1, "%s disableGesture: ERROR %08X \n", tag, + res); + goto END; + } + + logError(0, "%s disableGesture DONE! \n", tag); + + res = OK; + +END: + mutex_unlock(&gestureMask_mutex); + return res; + } else { + logError(1, + "%s disableGesture: Size not valid! %d > %d ERROR %08X \n", + tag, size, GESTURE_MASK_SIZE); + return ERROR_OP_NOT_ALLOW; + } +} + +/** + * Perform all the steps required to put the chip in gesture mode + * @param reload if set to 1, before entering in gesture mode it will re-enable in the FW the last defined gesture mask + * @return OK if success or an error code which specify the type of error encountered + */ +int enterGestureMode(int reload) +{ + int res, ret; + + res = fts_disableInterruptNoSync(); + if (res < OK) { + logError(1, "%s enterGestureMode: ERROR %08X \n", tag, + res | ERROR_DISABLE_INTER); + return res | ERROR_DISABLE_INTER; + } + + if (reload == 1 || refreshGestureMask == 1) { + + res = enableGesture(NULL, 0); + if (res < OK) { + logError(1, + "%s enterGestureMode: enableGesture ERROR %08X \n", + tag, res); + goto END; + } + + refreshGestureMask = 0; + } + + res = setScanMode(SCAN_MODE_LOW_POWER, 0); + if (res < OK) { + logError(1, + "%s enterGestureMode: enter gesture mode ERROR %08X \n", + tag, res); + goto END; + } + + res = OK; +END: + ret = fts_enableInterrupt(); + if (ret < OK) { + logError(1, + "%s enterGestureMode: fts_enableInterrupt ERROR %08X \n", + tag, res | ERROR_ENABLE_INTER); + res |= ret | ERROR_ENABLE_INTER; + } + + return res; +} + +/** + * Check if one or more Gesture IDs are currently enabled in gesture_mask + * @return FEAT_ENABLE if one or more gesture ids are enabled, FEAT_DISABLE if all the gesture ids are currently disabled + */ +int isAnyGestureActive(void) +{ + int res = 0; + + while (res < (GESTURE_MASK_SIZE - 1) && gesture_mask[res] == 0) { + res++; + } + + if (gesture_mask[res] != 0) { + logError(0, + "%s %s: Active Gestures Found! gesture_mask[%d] = %02X !\n", + tag, __func__, res, gesture_mask[res]); + return FEAT_ENABLE; + } else { + logError(0, "%s %s: All Gestures Disabled!\n", tag, __func__); + return FEAT_DISABLE; + } +} + +/** + * Read from the frame buffer the gesture coordinates pairs of the points draw by an user when a gesture is detected + * @param event pointer to a byte array which contains the gesture event reported by the fw when a gesture is detected + * @return OK if success or an error code which specify the type of error encountered + */ +int readGestureCoords(u8 *event) +{ + int i = 0; + u64 address = 0; + int res; + + u8 val[GESTURE_MAX_COORDS_PAIRS_REPORT * 4]; + + if (event[0] == EVT_ID_USER_REPORT && event[1] == EVT_TYPE_USER_GESTURE) { + address = (event[4] << 8) | event[3]; + gesture_coords_reported = event[5]; + if (gesture_coords_reported > GESTURE_MAX_COORDS_PAIRS_REPORT) { + logError(1, + "%s %s: FW reported more than %d points for the gestures! Decreasing to %d \n", + tag, __func__, gesture_coords_reported, + GESTURE_MAX_COORDS_PAIRS_REPORT); + gesture_coords_reported = + GESTURE_MAX_COORDS_PAIRS_REPORT; + } + + logError(1, "%s %s: Offset: %08X , coords pairs = %d\n", tag, + __func__, address, gesture_coords_reported); + + res = fts_writeReadU8UX(FTS_CMD_FRAMEBUFFER_R, BITS_16, address, val, (gesture_coords_reported * 2 * 2), DUMMY_FRAMEBUFFER); + if (res < OK) { + logError(1, + "%s %s: Cannot read the coordinates! ERROR %08X \n", + tag, __func__, res); + gesture_coords_reported = ERROR_OP_NOT_ALLOW; + return res; + } + + for (i = 0; i < gesture_coords_reported; i++) { + gesture_coordinates_x[i] = + (((u16) val[i * 2 + 1]) & 0x0F) << 8 | + (((u16) val[i * 2]) & 0xFF); + gesture_coordinates_y[i] = (((u16) + val[gesture_coords_reported + * 2 + i * 2 + + 1]) & 0x0F) << 8 | + (((u16) + val[gesture_coords_reported * 2 + i * 2]) & 0xFF); + } + + logError(1, "%s %s: Reading Gesture Coordinates DONE! \n", tag, + __func__); + return OK; + + } else { + logError(1, + "%s %s: The event passsed as argument is invalid! ERROR %08X \n", + tag, __func__, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + +} + +/** + * Return the coordinates of the points stored during the last detected gesture + * @param x output parameter which will store the address of the array containing the x coordinates + * @param y output parameter which will store the address of the array containing the y coordinates + * @return the number of points (x,y) stored and therefore the size of the x and y array returned. + */ +int getGestureCoords(u16 **x, u16 **y) +{ + *x = gesture_coordinates_x; + *y = gesture_coordinates_y; + logError(1, + "%s %s: Number of gesture coordinates pairs returned = %d \n", + tag, __func__, gesture_coords_reported); + return gesture_coords_reported; +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsGesture.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsGesture.h new file mode 100644 index 000000000000..226c3b0b1b60 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsGesture.h @@ -0,0 +1,38 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS Gesture Utilities * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsGesture.h +* \brief Contains all the macro and prototypes to handle the Gesture Detection features +*/ + +#ifndef FTS_GESTURE_H_ +#define FTS_GESTURE_H_ + +#include "ftsHardware.h" + +#define GESTURE_MASK_SIZE 4 + +#define GESTURE_MAX_COORDS_PAIRS_REPORT 100 + +int updateGestureMask(u8 *mask, int size, int en); +int disableGesture(u8 *mask, int size); +int enableGesture(u8 *mask, int size); +int enterGestureMode(int reload); +int isAnyGestureActive(void); +int readGestureCoords(u8 *event); +int getGestureCoords(u16 **x, u16 **y); + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsHardware.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsHardware.h new file mode 100644 index 000000000000..40c9e014cff7 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsHardware.h @@ -0,0 +1,191 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* HW related data * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsHardware.h +* \brief Contains all the definitions and information related to the IC from an hardware point of view +*/ + +#ifndef FTS_HARDWARE_H +#define FTS_HARDWARE_H + +/*DIGITAL CHIP INFO*/ +#define DCHIP_ID_0 0x36 /*LSB chip ID for FTM5*/ +#define DCHIP_ID_1 0x39 /*MSB chip ID for FTM5*/ + +#define DCHIP_FW_VER_BYTE 2 /*number of bytes of the fw versions*/ + +/*CHUNKS*/ +#define READ_CHUNK 1024 /*chunk dimension of a single i2c read, max allowed value is 2kB*/ +#define WRITE_CHUNK 1024 /*chunk dimension of a single i2c write, max allowed value is 2kB*/ +#define MEMORY_CHUNK 1024 /*chunk dimenasion of a single i2c write on mem, max allowed value is 2kB*/ + +/*PROTOCOL INFO*/ +#define I2C_INTERFACE /*comment if the chip use SPI bus*/ +#ifdef I2C_INTERFACE +#define I2C_SAD 0x49 /*slave address of the IC*/ +#else +#define SPI4_WIRE /*comment if the master is SPI3 wires (MOSI and MISO share same line)*/ +#define SPI_DELAY_CS 10 /*time in usec to wait before rising the CS*/ +#define SPI_CLOCK_FREQ 7000000 /*clock frequency in Hz of the SPI bus*/ +#endif + +#define IER_ENABLE 0x41 /*value to write in IER_ADDR to enable the interrupts*/ +#define IER_DISABLE 0x00 /*value to write in IER_ADDR to disable the interrupts*/ + +/*FLASH COMMAND*/ +/** @defgroup flash_command Flash Commands + * All the commands that works with the flash of the IC + * @{ + */ +#define FLASH_CMD_UNLOCK 0xF7 + +#define FLASH_CMD_READ_REGISTER 0xFA +#define FLASH_CMD_WRITE_REGISTER 0xFA + +/*FLASH UNLOCK PARAMETER*/ +#define FLASH_UNLOCK_CODE0 0x25 +#define FLASH_UNLOCK_CODE1 0x20 +#define FLASH_UNLOCK_CODE2 0x6B +#define FLASH_UNLOCK_CODE3 0x00 + +#define FLASH_UVLO_ENABLE_CODE0 0x1B +#define FLASH_UVLO_ENABLE_CODE1 0x66 +#define FLASH_AUTOPOWERDOWN_ENABLE_CODE0 0x68 +#define FLASH_AUTOPOWERDOWN_ENABLE_CODE1 0x13 +/*FLASH ERASE and DMA PARAMETER*/ +#define FLASH_ERASE_START 0x80 +#define FLASH_ERASE_CODE1 0xC0 +#define FLASH_DMA_CODE1 0xC0 +#define FLASH_ERASE_UNLOCK_CODE0 0xDE +#define FLASH_ERASE_UNLOCK_CODE1 0x03 +#define FLASH_ERASE_CODE0 0x6A +#define FLASH_DMA_CODE0 0x71 +#define FLASH_DMA_CONFIG 0x72 +#define FLASH_NUM_PAGE 32 /*number of pages in main flash*/ + +#define FLASH_CX_PAGE_START 28 /*starting page which contain Cx data*/ +#define FLASH_CX_PAGE_END 30 /*last page which contain Cx data*/ +#define FLASH_PANEL_PAGE_START 26 /*starting page which contain Panel Init data*/ +#define FLASH_PANEL_PAGE_END 27 /*last page which contain Panel Init data*/ + +/** @} */ + +/*FLASH ADDRESS*/ + +#define FLASH_ADDR_CODE 0x00000000 /*starting address (words) in the flash of the code in FTI*/ +#define FLASH_ADDR_CONFIG 0x00007C00 /*starting address (words) in the flash of the config in FTI*/ +#define FLASH_ADDR_CX 0x00007000 /*starting address (words) in the flash of the Init data in FTI*/ + +/*SIZES FW, CODE, CONFIG, MEMH*/ +/** @defgroup fw_file FW file info + * All the info related to the fw file + * @{ + */ + +#define FW_HEADER_SIZE 64 /*dimension of the header of the .fts file*/ +#define FW_HEADER_SIGNATURE 0xAA55AA55 /*header signature*/ +#define FW_FTB_VER 0x00000001 /*.ftb version*/ +#define FW_BYTES_ALLIGN 4 /*allignment of the info*/ +#define FW_BIN_VER_OFFSET 16 /*offset of the fw version in the .ftb file*/ +#define FW_BIN_CONFIG_ID_OFFSET 20 /*offset of the config id in the .ftb file*/ +#define FW_CX_VERSION (16 + 4) /*offset of CX version in the sec2 of FW file*/ + +/** @} */ + +/*FIFO*/ +#define FIFO_EVENT_SIZE 8 /*number of bytes of one event*/ +#define FIFO_DEPTH 32 /*max number of events that the FIFO can collect before going in overflow in FTM5*/ + +#ifdef I2C_INTERFACE +#define FIFO_CMD_READALL 0x86 /*command to read all the events in the FIFO*/ +#else +#define FIFO_CMD_READALL 0x87 /*command to read all the events in the FIFO*/ +#endif +#define FIFO_CMD_READONE FIFO_CMD_READALL /*commad to read one event from FIFO*/ + +/*OP CODES FOR MEMORY (based on protocol)*/ +#ifdef I2C_INTERFACE +#define FTS_CMD_HW_REG_R 0xFA /*command to read an hw register if FTI*/ +#define FTS_CMD_HW_REG_W 0xFA /*command to write an hw register if FTI*/ +#define FTS_CMD_FRAMEBUFFER_R 0xA6 /*command to read the framebuffer if FTI*/ +#define FTS_CMD_CONFIG_R 0xA8 /*command to read the config memory if FTI*/ +#define FTS_CMD_CONFIG_W 0xA8 /*command to write the config memory if FTI*/ +#else +#define FTS_CMD_HW_REG_R 0xFB /*command to read an hw register if FTI*/ +#define FTS_CMD_HW_REG_W 0xFA /*command to write an hw register if FTI*/ +#define FTS_CMD_FRAMEBUFFER_R 0xA7 /*command to read the framebuffer if FTI*/ +#define FTS_CMD_CONFIG_R 0xA9 /*command to read the config memory if FTI*/ +#define FTS_CMD_CONFIG_W 0xA8 /*command to write the config memory if FTI*/ +#endif + +/*DUMMY BYTES DATA*/ + +#ifndef I2C_INTERFACE +#define DUMMY_HW_REG 1 /*1 if the first byte read from HW register is dummy*/ +#define DUMMY_FRAMEBUFFER 1 /*1 if the first byte read from Frame buffer is dummy*/ +#define DUMMY_CONFIG 1 /*1 if the first byte read from Config Memory is dummy*/ +#define DUMMY_FIFO 1 /*1 if the first byte read from FIFO is dummy*/ +#else +#define DUMMY_HW_REG 0 /*1 if the first byte read from HW register is dummy*/ +#define DUMMY_FRAMEBUFFER 0 /*1 if the first byte read from Frame buffer is dummy*/ +#define DUMMY_CONFIG 0 /*1 if the first byte read from Config Memory is dummy*/ +#define DUMMY_FIFO 0 /*1 if the first byte read from FIFO is dummy*/ +#endif + +/** @defgroup hw_adr HW Address + * @ingroup address + * Important addresses of hardware registers (and sometimes their important values) + * @{ + */ + +/*IMPORTANT HW ADDRESSES (u64)*/ +#define ADDR_FRAMEBUFFER ((u64)0x0000000000000000) /*frame buffer address in memory*/ +#define ADDR_ERROR_DUMP ((u64)0x000000000000EF80) /*start address dump error log*/ + +/*SYSTEM RESET INFO*/ +#define ADDR_SYSTEM_RESET ((u64)0x0000000020000024) /*address of System control register in FTI*/ +#define SYSTEM_RESET_VALUE 0x80 /*value to write in SYSTEM_RESET_ADDRESS to perform a system reset in FTM5*/ + +/*REMAP REGISTER*/ +#define ADDR_BOOT_OPTION ((u64)0x0000000020000025) /*address of Boot option register in SONIA*/ + +/*INTERRUPT INFO*/ +#define ADDR_IER ((u64)0x0000000020000029) /*address of the Interrupt enable register in FTMI*/ + +/*Chip ID/Fw Version*/ +#define ADDR_DCHIP_ID ((u64)0x0000000020000000) /*chip id address for FTI*/ +#define ADDR_DCHIP_FW_VER ((u64)0x0000000020000004) /*fw version address for FTI*/ + +/*INTERFACE REGISTER*/ +#define ADDR_ICR ((u64)0x000000002000002D) /*address of Device control register to set the comunication protocol (SPI/I2C)*/ +#define SPI4_MASK 0x02 /*bit to set spi4*/ + +/*CRC ADDR*/ +#define ADDR_CRC ((u64)0x0000000020000078) /*address of the CRC control register in FTI*/ +#define CRC_MASK 0x03 /*bitmask which reveal if there is a CRC error in the flash*/ + +#define ADDR_CONFIG_OFFSET ((u64)0x0000000000000000) /*config address in memory if FTI*/ + +#define ADDR_GPIO_INPUT ((u64)0x0000000020000030) /*address of GPIO input register*/ +#define ADDR_GPIO_DIRECTION ((u64)0x0000000020000032) /*address of GPIO direction register*/ +#define ADDR_GPIO_PULLUP ((u64)0x0000000020000034) /*address of GPIO pullup register*/ +#define ADDR_GPIO_CONFIG_REG0 ((u64)0x000000002000003D) /*address of GPIO config register*/ +#define ADDR_GPIO_CONFIG_REG2 ((u64)0x000000002000003F) /*address of GPIO config register*/ + + +/**@}*/ + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsIO.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsIO.c new file mode 100644 index 000000000000..57cee43ae04c --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsIO.c @@ -0,0 +1,911 @@ +/* + + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * I2C/SPI Communication * + * * + ************************************************************************** + ************************************************************************** + + */ + +/*! +* \file ftsIO.c +* \brief Contains all the functions which handle with the I2C/SPI communication +*/ + +#include "ftsSoftware.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef I2C_INTERFACE +#include +#include +static u16 I2CSAD; +#include +#endif + +static void *client; + +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsHardware.h" +#include "ftsIO.h" + +extern struct fts_ts_info *fts_info; +static struct mutex rw_lock; +static u8 *buf1; +static u8 *buf2; + + +/** +* Initialize the static client variable of the fts_lib library in order to allow any i2c/spi transaction in the driver. (Must be called in the probe) +* @param clt pointer to i2c_client or spi_device struct which identify the bus slave device +* @return OK +*/ +int openChannel(void *clt) +{ + client = clt; +#ifdef I2C_INTERFACE + I2CSAD = ((struct i2c_client *)clt)->addr; + logError(0, "%s openChannel: SAD: %02X \n", tag, I2CSAD); +#else + logError(1, "%s %s: spi_master: flags = %04X !\n", tag, __func__, + ((struct spi_device *)client)->master->flags); + logError(1, + "%s %s: spi_device: max_speed = %d chip select = %02X bits_per_words = %d mode = %04X !\n", + tag, __func__, ((struct spi_device *)client)->max_speed_hz, + ((struct spi_device *)client)->chip_select, + ((struct spi_device *)client)->bits_per_word, + ((struct spi_device *)client)->mode); + logError(1, "%s openChannel: completed! \n", tag); +#endif + mutex_init(&rw_lock); + + if (!buf1) + buf1 = (u8 *)kzalloc(PAGE_SIZE, GFP_ATOMIC); + if (!buf2) + buf2 = (u8 *)kzalloc(PAGE_SIZE, GFP_ATOMIC); + if (!buf1 || !buf2) + return ERROR_ALLOC; + + return OK; +} + +#ifdef I2C_INTERFACE +/** +* Change the I2C slave address which will be used during the transaction (For Debug Only) +* @param sad new slave address id +* @return OK +*/ +int changeSAD(u8 sad) +{ + I2CSAD = sad; + return OK; +} +#endif + +/** +* Retrieve the pointer to the device struct of the IC +* @return a the device struct pointer if client was previously set or NULL in all the other cases +*/ +struct device *getDev() +{ + if (client != NULL) + return &(getClient()->dev); + else + return NULL; +} + +#ifdef I2C_INTERFACE +/** +* Retrieve the pointer of the i2c_client struct representing the IC as i2c slave +* @return client if it was previously set or NULL in all the other cases +*/ +struct i2c_client *getClient() +{ + if (client != NULL) + return (struct i2c_client *)client; + else + return NULL; +} +#else +/** +* Retrieve the pointer of the spi_device struct representing the IC as spi slave +* @return client if it was previously set or NULL in all the other cases +*/ +struct spi_device *getClient() +{ + if (client != NULL) + return (struct spi_device *)client; + else + return NULL; +} +#endif + +/****************** New I2C API *********************/ + +/** +* Perform a direct bus read +* @param outBuf pointer of a byte array which should contain the byte read from the IC +* @param byteToRead number of bytes to read +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_read(u8 *outBuf, int byteToRead) +{ + int ret = -1; + int retry = 0; + +#ifdef I2C_INTERFACE + struct i2c_msg I2CMsg[1]; + + I2CMsg[0].addr = (__u16) I2CSAD; + I2CMsg[0].flags = (__u16) I2C_M_RD; + I2CMsg[0].len = (__u16) byteToRead; + I2CMsg[0].buf = (__u8 *) outBuf; +#else + struct spi_message msg; + struct spi_transfer transfer[1] = { {0} }; + + spi_message_init(&msg); + + transfer[0].len = byteToRead; + transfer[0].delay_usecs = SPI_DELAY_CS; + transfer[0].tx_buf = NULL; + transfer[0].rx_buf = outBuf; + spi_message_add_tail(&transfer[0], &msg); +#endif + + if (client == NULL) + return ERROR_BUS_O; + while (retry < I2C_RETRY && ret < OK) { + +#ifdef I2C_INTERFACE + ret = i2c_transfer(getClient()->adapter, I2CMsg, 1); +#else + ret = spi_sync(getClient(), &msg); +#endif + + retry++; + if (ret < OK) + mdelay(I2C_WAIT_BEFORE_RETRY); + } + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ERROR_BUS_R); + return ERROR_BUS_R; + } + return OK; + +} + +/** +* Perform a bus write followed by a bus read without a stop condition +* @param cmd byte array containing the command to write +* @param cmdLength size of cmd +* @param outBuf pointer of a byte array which should contain the bytes read from the IC +* @param byteToRead number of bytes to read +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_writeRead(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead) +{ + int ret = -1; + int retry = 0; + +#ifdef I2C_INTERFACE + struct i2c_msg I2CMsg[2]; + + I2CMsg[0].addr = (__u16) I2CSAD; + I2CMsg[0].flags = (__u16) 0; + I2CMsg[0].len = (__u16) cmdLength; + I2CMsg[0].buf = (__u8 *) cmd; + + I2CMsg[1].addr = (__u16) I2CSAD; + I2CMsg[1].flags = I2C_M_RD; + I2CMsg[1].len = byteToRead; + I2CMsg[1].buf = (__u8 *) outBuf; + +#else + struct spi_message msg; + struct spi_transfer transfer[2] = { {0}, {0} }; + + spi_message_init(&msg); + + transfer[0].len = cmdLength; + transfer[0].tx_buf = cmd; + transfer[0].rx_buf = NULL; + spi_message_add_tail(&transfer[0], &msg); + + transfer[1].len = byteToRead; + transfer[1].delay_usecs = SPI_DELAY_CS; + transfer[1].tx_buf = NULL; + transfer[1].rx_buf = outBuf; + spi_message_add_tail(&transfer[1], &msg); + +#endif + + if (client == NULL) + return ERROR_BUS_O; + + while (retry < I2C_RETRY && ret < OK) { +#ifdef I2C_INTERFACE + ret = i2c_transfer(getClient()->adapter, I2CMsg, 2); +#else + ret = spi_sync(getClient(), &msg); +#endif + + retry++; + if (ret < OK) + mdelay(I2C_WAIT_BEFORE_RETRY); + } + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ERROR_BUS_WR); + return ERROR_BUS_WR; + } + return OK; +} + +/** +* Perform a bus write +* @param cmd byte array containing the command to write +* @param cmdLength size of cmd +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_write(u8 *cmd, int cmdLength) +{ + int ret = -1; + int retry = 0; + +#ifdef I2C_INTERFACE + struct i2c_msg I2CMsg[1]; + + I2CMsg[0].addr = (__u16) I2CSAD; + I2CMsg[0].flags = (__u16) 0; + I2CMsg[0].len = (__u16) cmdLength; + I2CMsg[0].buf = (__u8 *) cmd; +#else + struct spi_message msg; + struct spi_transfer transfer[1] = { {0} }; + + spi_message_init(&msg); + + transfer[0].len = cmdLength; + transfer[0].delay_usecs = SPI_DELAY_CS; + transfer[0].tx_buf = cmd; + transfer[0].rx_buf = NULL; + spi_message_add_tail(&transfer[0], &msg); +#endif + + if (client == NULL) + return ERROR_BUS_O; + while (retry < I2C_RETRY && ret < OK) { +#ifdef I2C_INTERFACE + ret = i2c_transfer(getClient()->adapter, I2CMsg, 1); +#else + ret = spi_sync(getClient(), &msg); +#endif + + retry++; + if (ret < OK) + mdelay(I2C_WAIT_BEFORE_RETRY); + } + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ERROR_BUS_W); + return ERROR_BUS_W; + } + return OK; +} +#ifdef CONFIG_I2C_BY_DMA +/** + * same as above but can be used when enable DMA. + */ +int fts_read_dma_safe(u8 *outBuf, int byteToRead) +{ + + int ret; + struct fts_dma_buf *dma = fts_info->dma_buf; + u8 *malcBuf = dma->rdBuf; + u8 *tmpBuf = NULL; + u8 *finalBuf; + + mutex_lock(&dma->dmaBufLock); + /*use malloc buf*/ + if (byteToRead > 1) { + /*extend malloc buf*/ + if (unlikely(byteToRead > PAGE_SIZE)) { + tmpBuf = kzalloc(byteToRead, GFP_KERNEL); + if (!tmpBuf) { + logError(1, "%s %s:ERROR alloc mem failed!", tag, __func__); + mutex_unlock(&dma->dmaBufLock); + return ERROR_ALLOC; + } + finalBuf = tmpBuf; + } else { + finalBuf = malcBuf; + } + } else { + finalBuf = outBuf; + } + + ret = fts_read(finalBuf, byteToRead); + if ((ret == OK) && (byteToRead > 1)) { + memcpy(outBuf, finalBuf, byteToRead); + } + if (unlikely(tmpBuf)) + kfree(tmpBuf); + mutex_unlock(&dma->dmaBufLock); + + return ret; +} + +int fts_writeRead_dma_safe(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead) +{ + int ret; + struct fts_dma_buf *dma = fts_info->dma_buf; + u8 *malcRdBuf = dma->rdBuf; + u8 *malcWrBuf = dma->wrBuf; + u8 *rdBuf, *tmpRdBuf = NULL; + u8 *wrBuf, *tmpWrBuf = NULL; + + mutex_lock(&dma->dmaBufLock); + if (cmdLength > 1) { + if (unlikely(cmdLength > PAGE_SIZE)) { + tmpWrBuf = kzalloc(cmdLength, GFP_KERNEL); + if (!tmpWrBuf) { + logError(1, "%s %s:ERROR alloc mem failed!", tag, __func__); + mutex_unlock(&dma->dmaBufLock); + return ERROR_ALLOC; + } + wrBuf = tmpWrBuf; + } else { + wrBuf = malcWrBuf; + } + memcpy(wrBuf, cmd, cmdLength); + } else { + wrBuf = cmd; + } + + if (byteToRead > 1) { + if (unlikely(byteToRead > PAGE_SIZE)) { + tmpRdBuf = kzalloc(byteToRead, GFP_KERNEL); + if (!tmpRdBuf) { + logError(1, "%s %s:ERROR alloc mem failed!", tag, __func__); + if (tmpWrBuf) + kfree(tmpWrBuf); + mutex_unlock(&dma->dmaBufLock); + return ERROR_ALLOC; + } + rdBuf = tmpRdBuf; + } else { + rdBuf = malcRdBuf; + } + } else { + rdBuf = outBuf; + } + + ret = fts_writeRead(wrBuf, cmdLength, rdBuf, byteToRead); + if ((ret == OK) && (byteToRead > 1)) + memcpy(outBuf, rdBuf, byteToRead); + + if (unlikely(tmpRdBuf)) + kfree(tmpRdBuf); + if (unlikely(tmpWrBuf)) + kfree(tmpWrBuf); + mutex_unlock(&dma->dmaBufLock); + + return ret; +} + +int fts_write_dma_safe(u8 *cmd, int cmdLength) +{ + int ret; + struct fts_dma_buf *dma = fts_info->dma_buf; + u8 *malcBuf = dma->wrBuf; + u8 *tmpBuf = NULL; + u8 *finalBuf; + + mutex_lock(&dma->dmaBufLock); + /*use malloc buf*/ + if (cmdLength > 1) { + /*extend malloc buf*/ + if (unlikely(cmdLength > PAGE_SIZE)) { + tmpBuf = kzalloc(cmdLength, GFP_KERNEL); + if (!tmpBuf) { + logError(1, "%s %s:ERROR alloc mem failed!", tag, __func__); + mutex_unlock(&dma->dmaBufLock); + return ERROR_ALLOC; + } + finalBuf = tmpBuf; + } else { + finalBuf = malcBuf; + } + memcpy(finalBuf, cmd, cmdLength); + } else { + finalBuf = cmd; + } + + ret = fts_write(finalBuf, cmdLength); + + if (unlikely(tmpBuf)) + kfree(tmpBuf); + mutex_unlock(&dma->dmaBufLock); + + + return ret; +} +#else +int fts_read_dma_safe(u8 *outBuf, int byteToRead) +{ + return fts_read(outBuf, byteToRead); +} +int fts_writeRead_dma_safe(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead) +{ + return fts_writeRead(cmd, cmdLength, outBuf, byteToRead); +} +int fts_write_dma_safe(u8 *cmd, int cmdLength) +{ + return fts_write(cmd, cmdLength); +} +#endif + +/** +* Write a FW command to the IC and check automatically the echo event +* @param cmd byte array containing the command to send +* @param cmdLength size of cmd +* @return OK if success, or an error code which specify the type of error encountered +*/ +int fts_writeFwCmd(u8 *cmd, int cmdLength) +{ + int ret = -1; + int ret2 = -1; + int retry = 0; +#ifdef I2C_INTERFACE + struct i2c_msg I2CMsg[1]; + + I2CMsg[0].addr = (__u16) I2CSAD; + I2CMsg[0].flags = (__u16) 0; + I2CMsg[0].len = (__u16) cmdLength; + I2CMsg[0].buf = (__u8 *) cmd; +#else + struct spi_message msg; + struct spi_transfer transfer[1] = { {0} }; + + spi_message_init(&msg); + + transfer[0].len = cmdLength; + transfer[0].delay_usecs = SPI_DELAY_CS; + transfer[0].tx_buf = cmd; + transfer[0].rx_buf = NULL; + spi_message_add_tail(&transfer[0], &msg); +#endif + + if (client == NULL) + return ERROR_BUS_O; + resetErrorList(); + while (retry < I2C_RETRY && (ret < OK || ret2 < OK)) { +#ifdef I2C_INTERFACE + ret = i2c_transfer(getClient()->adapter, I2CMsg, 1); +#else + ret = spi_sync(getClient(), &msg); +#endif + retry++; + if (ret >= 0) + ret2 = checkEcho(cmd, cmdLength); + if (ret < OK || ret2 < OK) + mdelay(I2C_WAIT_BEFORE_RETRY); + } + if (ret < 0) { + logError(1, "%s fts_writeFwCmd: ERROR %08X\n", tag, + ERROR_BUS_W); + return ERROR_BUS_W; + } + if (ret2 < OK) { + logError(1, "%s fts_writeFwCmd: check echo ERROR %08X\n", tag, + ret2); + return ret2; + } + return OK; +} + +/** +* Perform two bus write and one bus read without any stop condition +* In case of FTI this function is not supported and the same sequence can be achieved calling fts_write followed by an fts_writeRead. +* @param writeCmd1 byte array containing the first command to write +* @param writeCmdLength size of writeCmd1 +* @param readCmd1 byte array containing the second command to write +* @param readCmdLength size of readCmd1 +* @param outBuf pointer of a byte array which should contain the bytes read from the IC +* @param byteToRead number of bytes to read +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_writeThenWriteRead(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1, + int readCmdLength, u8 *outBuf, int byteToRead) +{ + int ret = -1; + int retry = 0; + +#ifdef I2C_INTERFACE + struct i2c_msg I2CMsg[3]; + + I2CMsg[0].addr = (__u16) I2CSAD; + I2CMsg[0].flags = (__u16) 0; + I2CMsg[0].len = (__u16) writeCmdLength; + I2CMsg[0].buf = (__u8 *) writeCmd1; + + I2CMsg[1].addr = (__u16) I2CSAD; + I2CMsg[1].flags = (__u16) 0; + I2CMsg[1].len = (__u16) readCmdLength; + I2CMsg[1].buf = (__u8 *) readCmd1; + + I2CMsg[2].addr = (__u16) I2CSAD; + I2CMsg[2].flags = I2C_M_RD; + I2CMsg[2].len = byteToRead; + I2CMsg[2].buf = (__u8 *) outBuf; +#else + struct spi_message msg; + struct spi_transfer transfer[3] = { {0}, {0}, {0} }; + + spi_message_init(&msg); + + transfer[0].len = writeCmdLength; + transfer[0].tx_buf = writeCmd1; + transfer[0].rx_buf = NULL; + spi_message_add_tail(&transfer[0], &msg); + + transfer[1].len = readCmdLength; + transfer[1].tx_buf = readCmd1; + transfer[1].rx_buf = NULL; + spi_message_add_tail(&transfer[1], &msg); + + transfer[2].len = byteToRead; + transfer[2].delay_usecs = SPI_DELAY_CS; + transfer[2].tx_buf = NULL; + transfer[2].rx_buf = outBuf; + spi_message_add_tail(&transfer[2], &msg); +#endif + + if (client == NULL) + return ERROR_BUS_O; + while (retry < I2C_RETRY && ret < OK) { +#ifdef I2C_INTERFACE + ret = i2c_transfer(getClient()->adapter, I2CMsg, 3); +#else + ret = spi_sync(getClient(), &msg); +#endif + retry++; + if (ret < OK) + mdelay(I2C_WAIT_BEFORE_RETRY); + } + + if (ret < 0) { + logError(1, "%s %s: ERROR %08X\n", tag, __func__, ERROR_BUS_WR); + return ERROR_BUS_WR; + } + return OK; + +} + +/** +* Perform a chunked write with one byte op code and 1 to 8 bytes address +* @param cmd byte containing the op code to write +* @param addrSize address size in byte +* @param address the starting address +* @param data pointer of a byte array which contain the bytes to write +* @param dataSize size of data +* @return OK if success or an error code which specify the type of error encountered +*/ +/* this function works only if the address is max 8 bytes */ +int fts_writeU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *data, + int dataSize) +{ + + u8 *finalCmd = buf1; + int remaining = dataSize; + int toWrite = 0, i = 0; + + mutex_lock(&rw_lock); + if (addrSize <= sizeof(u64)) { + + while (remaining > 0) { + if (remaining >= WRITE_CHUNK) { + toWrite = WRITE_CHUNK; + remaining -= WRITE_CHUNK; + } else { + toWrite = remaining; + remaining = 0; + } + + finalCmd[0] = cmd; + logError(0, "%s %s: addrSize = %d \n", tag, __func__, + addrSize); + for (i = 0; i < addrSize; i++) { + finalCmd[i + 1] = + (u8) ((address >> ((addrSize - 1 - i) * 8)) + & 0xFF); + logError(1, "%s %s: cmd[%d] = %02X \n", tag, + __func__, i + 1, finalCmd[i + 1]); + } + + memcpy(&finalCmd[addrSize + 1], data, toWrite); + + if (fts_write(finalCmd, 1 + addrSize + toWrite) < OK) { + logError(1, "%s %s: ERROR %08X \n", tag, + __func__, ERROR_BUS_W); + mutex_unlock(&rw_lock); + return ERROR_BUS_W; + } + + address += toWrite; + + data += toWrite; + } + } else { + logError(1, + "%s %s: address size bigger than max allowed %d... ERROR %08X \n", + tag, __func__, sizeof(u64), ERROR_OP_NOT_ALLOW); + } + mutex_unlock(&rw_lock); + + return OK; +} + +/** +* Perform a chunked write read with one byte op code and 1 to 8 bytes address and dummy byte support. +* @param cmd byte containing the op code to write +* @param addrSize address size in byte +* @param address the starting address +* @param outBuf pointer of a byte array which contain the bytes to read +* @param byteToRead number of bytes to read +* @param hasDummyByte if the first byte of each reading is dummy (must be skipped) set to 1, otherwise if it is valid set to 0 (or any other value) +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_writeReadU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *outBuf, + int byteToRead, int hasDummyByte) +{ + u8 *finalCmd = buf1; + u8 *buff = buf2; + int remaining = byteToRead; + int toRead = 0, i = 0; + + mutex_lock(&rw_lock); + while (remaining > 0) { + if (remaining >= READ_CHUNK) { + toRead = READ_CHUNK; + remaining -= READ_CHUNK; + } else { + toRead = remaining; + remaining = 0; + } + + finalCmd[0] = cmd; + for (i = 0; i < addrSize; i++) { + finalCmd[i + 1] = + (u8) ((address >> ((addrSize - 1 - i) * 8)) & 0xFF); + } + + if (hasDummyByte == 1) { + if (fts_writeRead + (finalCmd, 1 + addrSize, buff, toRead + 1) < OK) { + logError(1, + "%s %s: read error... ERROR %08X \n", + tag, __func__, ERROR_BUS_WR); + mutex_unlock(&rw_lock); + return ERROR_BUS_WR; + } + memcpy(outBuf, buff + 1, toRead); + } else { + if (fts_writeRead(finalCmd, 1 + addrSize, buff, toRead) + < OK) { + logError(1, + "%s %s: read error... ERROR %08X \n", + tag, __func__, ERROR_BUS_WR); + mutex_unlock(&rw_lock); + return ERROR_BUS_WR; + } + memcpy(outBuf, buff, toRead); + } + + address += toRead; + + outBuf += toRead; + } + + mutex_unlock(&rw_lock); + + return OK; +} + +/** +* Perform a chunked write followed by a second write with one byte op code for each write and 1 to 8 bytes address (the sum of the 2 address size of the two writes can not exceed 8 bytes) +* @param cmd1 byte containing the op code of first write +* @param addrSize1 address size in byte of first write +* @param cmd2 byte containing the op code of second write +* @param addrSize2 address size in byte of second write +* @param address the starting address +* @param data pointer of a byte array which contain the bytes to write +* @param dataSize size of data +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_writeU8UXthenWriteU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2, + AddrSize addrSize2, u64 address, u8 *data, + int dataSize) +{ + u8 *finalCmd1 = NULL; + u8 *finalCmd2 = buf1; + int remaining = dataSize; + int toWrite = 0, i = 0, ret = OK; + + mutex_lock(&rw_lock); + finalCmd1 = (u8 *)kzalloc(sizeof(u8) * 10, GFP_KERNEL); + if (!finalCmd1) { + ret = ERROR_ALLOC; + goto end; + } + + while (remaining > 0) { + if (remaining >= WRITE_CHUNK) { + toWrite = WRITE_CHUNK; + remaining -= WRITE_CHUNK; + } else { + toWrite = remaining; + remaining = 0; + } + + finalCmd1[0] = cmd1; + for (i = 0; i < addrSize1; i++) { + finalCmd1[i + 1] = + (u8) ((address >> + ((addrSize1 + addrSize2 - 1 - + i) * 8)) & 0xFF); + } + + finalCmd2[0] = cmd2; + for (i = addrSize1; i < addrSize1 + addrSize2; i++) { + finalCmd2[i - addrSize1 + 1] = + (u8) ((address >> + ((addrSize1 + addrSize2 - 1 - + i) * 8)) & 0xFF); + } + + memcpy(&finalCmd2[addrSize2 + 1], data, toWrite); + + if (fts_write(finalCmd1, 1 + addrSize1) < OK) { + logError(1, "%s %s: first write error... ERROR %08X \n", + tag, __func__, ERROR_BUS_W); + ret = ERROR_BUS_W; + goto end; + } + + if (fts_write(finalCmd2, 1 + addrSize2 + toWrite) < OK) { + logError(1, + "%s %s: second write error... ERROR %08X \n", + tag, __func__, ERROR_BUS_W); + ret = ERROR_BUS_W; + goto end; + } + + address += toWrite; + + data += toWrite; + } + +end: + if (finalCmd1) + kfree(finalCmd1); + mutex_unlock(&rw_lock); + + return ret; +} + +/** +* Perform a chunked write followed by a write read with one byte op code and 1 to 8 bytes address for each write and dummy byte support. +* @param cmd1 byte containing the op code of first write +* @param addrSize1 address size in byte of first write +* @param cmd2 byte containing the op code of second write read +* @param addrSize2 address size in byte of second write read +* @param address the starting address +* @param outBuf pointer of a byte array which contain the bytes to read +* @param byteToRead number of bytes to read +* @param hasDummyByte if the first byte of each reading is dummy (must be skipped) set to 1, otherwise if it is valid set to 0 (or any other value) +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_writeU8UXthenWriteReadU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2, + AddrSize addrSize2, u64 address, u8 *outBuf, + int byteToRead, int hasDummyByte) +{ + u8 *finalCmd1 = NULL; + u8 *finalCmd2 = NULL; + u8 *buff = buf1; + int remaining = byteToRead; + int toRead = 0, i = 0, ret = OK; + + mutex_lock(&rw_lock); + finalCmd1 = (u8 *)kzalloc(sizeof(u8) * 10, GFP_KERNEL); + if (!finalCmd1) { + ret = ERROR_ALLOC; + goto end; + } + finalCmd2 = (u8 *)kzalloc(sizeof(u8) * 10, GFP_KERNEL); + if (!finalCmd2) { + ret = ERROR_ALLOC; + goto end; + } + + while (remaining > 0) { + if (remaining >= READ_CHUNK) { + toRead = READ_CHUNK; + remaining -= READ_CHUNK; + } else { + toRead = remaining; + remaining = 0; + } + + finalCmd1[0] = cmd1; + for (i = 0; i < addrSize1; i++) { + finalCmd1[i + 1] = + (u8) ((address >> + ((addrSize1 + addrSize2 - 1 - + i) * 8)) & 0xFF); + } + + finalCmd2[0] = cmd2; + for (i = addrSize1; i < addrSize1 + addrSize2; i++) { + finalCmd2[i - addrSize1 + 1] = + (u8) ((address >> + ((addrSize1 + addrSize2 - 1 - + i) * 8)) & 0xFF); + } + + if (fts_write(finalCmd1, 1 + addrSize1) < OK) { + logError(1, "%s %s: first write error... ERROR %08X \n", + tag, __func__, ERROR_BUS_W); + ret = ERROR_BUS_W; + goto end; + } + + if (hasDummyByte == 1) { + if (fts_writeRead + (finalCmd2, 1 + addrSize2, buff, toRead + 1) < OK) { + logError(1, + "%s %s: read error... ERROR %08X \n", + tag, __func__, ERROR_BUS_WR); + ret = ERROR_BUS_WR; + goto end; + } + memcpy(outBuf, buff + 1, toRead); + } else { + if (fts_writeRead + (finalCmd2, 1 + addrSize2, buff, toRead) < OK) { + logError(1, + "%s %s: read error... ERROR %08X \n", + tag, __func__, ERROR_BUS_WR); + ret = ERROR_BUS_WR; + goto end; + } + memcpy(outBuf, buff, toRead); + } + + address += toRead; + + outBuf += toRead; + } + +end: + if (finalCmd1) + kfree(finalCmd1); + if (finalCmd2) + kfree(finalCmd2); + mutex_unlock(&rw_lock); + return ret; +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsIO.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsIO.h new file mode 100644 index 000000000000..954c2f5148de --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsIO.h @@ -0,0 +1,59 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* I2C/SPI Communication * +* * +************************************************************************** +************************************************************************** + +*/ +/*! +* \file ftsIO.h +* \brief Contains all the definitions and prototypes used and implemented in ftsIO.c +*/ + +#ifndef FTS_IO_H +#define FTS_IO_H + +#include "ftsSoftware.h" + +#define I2C_RETRY 3 +#define I2C_WAIT_BEFORE_RETRY 2 + +#ifdef I2C_INTERFACE +#include +#include +struct i2c_client *getClient(void); +#else +#include +struct spi_device *getClient(void); +#endif + + + +int openChannel(void *clt); +struct device *getDev(void); + + + +/*************** NEW I2C API ****************/ +int changeSAD(u8 sad); +int fts_read(u8 *outBuf, int byteToRead); +int fts_writeRead(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead); +int fts_write(u8 *cmd, int cmdLength); +int fts_read_dma_safe(u8 *outBuf, int byteToRead); +int fts_writeRead_dma_safe(u8 *cmd, int cmdLength, u8 *outBuf, int byteToRead); +int fts_write_dma_safe(u8 *cmd, int cmdLength); +int fts_writeFwCmd(u8 *cmd, int cmdLenght); +int fts_writeThenWriteRead(u8 *writeCmd1, int writeCmdLength, u8 *readCmd1, + int readCmdLength, u8 *outBuf, int byteToRead); +int fts_writeU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *data, int dataSize); +int fts_writeReadU8UX(u8 cmd, AddrSize addrSize, u64 address, u8 *outBuf, int byteToRead, int hasDummyByte); +int fts_writeU8UXthenWriteU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2, AddrSize addrSize2, u64 address, u8 *data, int dataSize); +int fts_writeU8UXthenWriteReadU8UX(u8 cmd1, AddrSize addrSize1, u8 cmd2, AddrSize addrSize2, u64 address, u8 *outBuf, int count, int hasDummyByte); +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsSoftware.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsSoftware.h new file mode 100644 index 000000000000..b270a2bcded1 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsSoftware.h @@ -0,0 +1,379 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FW related data * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsSoftware.h +* \brief Contains all the definitions and information related to the IC from a fw/driver point of view +*/ + + +#ifndef FTS_SOFTWARE_H +#define FTS_SOFTWARE_H +#include +#include "ftsHardware.h" + +typedef signed char i8; /*basic type that represent one signed byte (or 8 bits)*/ + +/** + * Enumerator which contains all the possible address length expressed in bytes. + */ +typedef enum { + NO_ADDR = 0, + BITS_8 = 1, + BITS_16 = 2, + BITS_24 = 3, + BITS_32 = 4, + BITS_40 = 5, + BITS_48 = 6, + BITS_56 = 7, + BITS_64 = 8 +} AddrSize; + +/******************** NEW API *********************/ + +/** @defgroup host_command Fw Host op codes + * Valid op codes for fw commands + * @{ + */ + +/** @defgroup scan_mode Scan Mode +* @ingroup host_command +* Set the scanning mode required according to the parameters +* @{ +*/ +#define FTS_CMD_SCAN_MODE 0xA0 /*OP Code to set scan mode*/ +/** @} */ + +/** @defgroup feat_sel Feature Select +* @ingroup host_command +* Set the system defined features to enable/disable according the parameters +* @{ +*/ +#define FTS_CMD_FEATURE 0xA2 /*OP code to set features*/ +/** @} */ + +/** @defgroup sys_cmd System Command +* @ingroup host_command +* Execute a system command to perform core tasks +* @{ +*/ +#define FTS_CMD_SYSTEM 0xA4 /*OP code to write s system command*/ + +#define FTS_CMD_LOCKDOWN_ID 0x70 +#define FTS_CMD_CUSTOM 0xC0 +/** @} */ + +/** @} */ + +/*SCAN MODE OPTION (0xA0)*/ +/** @defgroup scan_opt Scan Mode Option +* @ingroup scan_mode +* Valid scanning modes and their options +* @{ +*/ +#define SCAN_MODE_ACTIVE 0x00 /*Select the Active scanning mode*/ +#define SCAN_MODE_LOW_POWER 0x01 /*Select the low power scanning mode*/ +#define SCAN_MODE_JIG_1 0x02 /*Select the Jig test 1*/ +#define SCAN_MODE_LOCKED 0x03 /*Select the Scan mode which will be locked*/ +/** @}*/ + +/** @defgroup active_bitmask Active Mode Bitmask +* @ingroup scan_opt +* Bitmask to use to enables the specific scanning with the SCAN_MODE_ACTIVE option +* @{ +*/ +#define ACTIVE_MULTI_TOUCH 0x01 /*Bit 0 MS/SS scan*/ +#define ACTIVE_KEY 0x02 /*Bit 1 Key scan*/ +#define ACTIVE_HOVER 0x04 /*Bit 2 Hover scan*/ +#define ACTIVE_PROXIMITY 0x08 /*Bit 3 Proximity scan*/ +#define ACTIVE_FORCE 0x10 /*Bit 4 Force scan*/ +/** @}*/ + +/** @defgroup locked_opt Locked Mode Option +* @ingroup scan_opt +* Options to enable and lock specific scanning with the SCAN_MODE_LOCKED option +* @{ +*/ +#define LOCKED_ACTIVE 0x00 /*Active Scan Mode*/ +#define LOCKED_HOVER 0x01 /*Hover Scan Mode*/ +#define LOCKED_IDLE 0x02 /*Idle Scan Mode*/ +#define LOCKED_LP_DETECT 0x10 /*Low Power SS*/ +#define LOCKED_LP_ACTIVE 0x11 /*Low Power MS*/ +/** @}*/ + +/** @defgroup feat_opt Feature Selection Option +* @ingroup feat_sel +* System defined features that can be enable/disable +* @{ +*/ +#define FEAT_SEL_GLOVE 0x00 /*Glove Mode*/ +#define FEAT_SEL_COVER 0x01 /*Cover Mode*/ +#define FEAT_SEL_CHARGER 0x02 /*Charger Mode*/ +#define FEAT_SEL_GESTURE 0x03 /*Gesture Mode*/ +#define FEAT_SEL_GRIP 0x04 /*Grip Detection*/ +#define FEAT_SEL_STYLUS 0x07 /*Stylus Mode (this is a driver define, not available in FW)*/ +/** @}*/ + +#define FEAT_ENABLE 1 /*General value to enable a feature*/ +#define FEAT_DISABLE 0 /*General value to disable a feature*/ + +/** @defgroup charger_opt Charger Mode Option +* @ingroup feat_sel +* Option for Charger Mode, it is a bitmask where the each bit indicate a different kind of chager +* @{ +*/ +#define CHARGER_CABLE 0x01 /*normal usb charger*/ +#define CHARGER_WIRLESS 0x02 /*wireless charger*/ +/** @}*/ + +/** @defgroup gesture_opt Gesture Mode Option +* @ingroup feat_sel +* Gesture IDs of the predefined gesture recognized by the fw. +* The ID represent also the position of the corresponding bit in the gesture mask +* @{ +*/ +#define GEST_ID_UP_1F 0x01 /*Bottom to Top line*/ +#define GEST_ID_DOWN_1F 0x02 /*Top to bottom line*/ +#define GEST_ID_LEFT_1F 0x03 /*Right to left line*/ +#define GEST_ID_RIGHT_1F 0x04 /*Left to right line*/ +#define GEST_ID_DBLTAP 0x05 /*Double Tap*/ +#define GEST_ID_O 0x06 /*'O'*/ +#define GEST_ID_C 0x07 /*'C'*/ +#define GEST_ID_M 0x08 /*'M'*/ +#define GEST_ID_W 0x09 /*'W'*/ +#define GEST_ID_E 0x0A /*'e'*/ +#define GEST_ID_L 0x0B /*'L'*/ +#define GEST_ID_F 0x0C /*'F'*/ +#define GEST_ID_V 0x0D /*'V'*/ +#define GEST_ID_AT 0x0E /*'@'*/ +#define GEST_ID_S 0x0F /*'S'*/ +#define GEST_ID_Z 0x10 /*'Z'*/ +#define GEST_ID_LEFTBRACE 0x11 /*'<'*/ +#define GEST_ID_RIGHTBRACE 0x12 /*'>'*/ +#define GEST_ID_CARET 0x13 /*'^'*/ +#define GEST_ID_LONG_PRESS 0x18 /*'^'*/ +#define GEST_ID_SINGTAP 0x19 /*'^'*/ +/** @}*/ + +/** @defgroup sys_opt System Command Option +* @ingroup sys_cmd +* Valid System Command Parameters +* @{ +*/ +#define SYS_CMD_SPECIAL 0x00 /*Special Commands*/ +#define SYS_CMD_INT 0x01 /*FW Interrupt Control*/ +#define SYS_CMD_FORCE_CAL 0x02 /*Force Calibration*/ +#define SYS_CMD_CX_TUNING 0x03 /*CX initialization*/ +#define SYS_CMD_ITO 0x04 /*ITO test*/ +#define SYS_CMD_SAVE_FLASH 0x05 /*Saving to flash*/ +#define SYS_CMD_LOAD_DATA 0x06 /*Load Host data memory*/ +#define SYS_CMD_SPECIAL_TUNING 0x08 /*Perform some special tuning*/ +/** @} */ + +/** @defgroup sys_special_opt Special Command Option +* @ingroup sys_cmd +* Valid special command +* @{ +*/ +#define SPECIAL_SYS_RESET 0x00 /*System Reset triggered by the FW*/ +#define SPECIAL_FIFO_FLUSH 0x01 /*Flush of the FIFO*/ +#define SPECIAL_PANEL_INIT 0x02 /*Panel Initialization*/ +#define SPECIAL_FULL_PANEL_INIT 0x03 /*Full panel initialization*/ +/** @} */ + +#define CAL_MS_TOUCH 0x00 /*Mutual Sense Touch*/ +#define CAL_MS_LOW_POWER 0x01 /*Mutual Sense Touch in low power mode*/ +#define CAL_SS_TOUCH 0x02 /*Self Sense Touch*/ +#define CAL_SS_IDLE 0x03 /*Self Sense Touch in idle mode*/ +#define CAL_MS_KEY 0x04 /*Mutual Sense Key*/ +#define CAL_SS_KEY 0x05 /*Self Sense Key*/ +#define CAL_MS_FORCE 0x06 /*Mutual Sense Force*/ +#define CAL_SS_FORCE 0x07 /*Self Sense Force*/ + +/** @defgroup ito_opt ITO Test Option +* @ingroup sys_cmd +* Valid option for the ITO test +* @{ +*/ +#define ITO_FORCE_OPEN 0x00 /*Check if some force channels is open*/ +#define ITO_SENSE_OPEN 0x01 /*Check if some sense channels is open*/ +#define ITO_FORCE_GROUND 0x02 /*Check if some force channels is short to ground*/ +#define ITO_SENSE_GROUND 0x03 /*Check if some sense channels is short to ground*/ +#define ITO_FORCE_VDD 0x04 /*Check if some force channels is short to VDD*/ +#define ITO_SENSE_VDD 0x05 /*Check if some sense channels is short to VDD*/ +#define ITO_FORCE_FORCE 0x06 /*Check force to force channels*/ +#define ITO_FORCE_SENSE 0x07 /*Check force to sense channels*/ +#define ITO_SENSE_SENSE 0x08 /*Check sense to sense channels*/ +#define ITO_KEY_FORCE_OPEN 0x09 /*Check if some force channels used for the key is open*/ +#define ITO_KEY_SENSE_OPEN 0x0A /*Check if some sense channels used for the key is open*/ +/** @}*/ + +/** @defgroup save_opt Save to Flash Option +* @ingroup sys_cmd +* Valid option for saving data to the Flash +* @{ +*/ +#define SAVE_FW_CONF 0x01 /*Save the confing to the flash*/ +#define SAVE_CX 0x02 /*Save the CX to the flash*/ +#define SAVE_PANEL_CONF 0x04 /*Save the Panel configuration to the flash*/ +/** @}*/ + +/** @defgroup load_opt Load Host Data Option +* @ingroup sys_cmd +* Valid option to ask to the FW to load host data into the memory +* @{ +*/ +#define LOAD_SYS_INFO 0x01 /*Load System Info*/ +#define LOAD_CX_MS_TOUCH 0x10 /*Load MS Init Data for Active Mode*/ +#define LOAD_CX_MS_LOW_POWER 0x11 /*Load MS Init Data for Low Power Mode*/ +#define LOAD_CX_SS_TOUCH 0x12 /*Load SS Init Data for Active Mode*/ +#define LOAD_CX_SS_TOUCH_IDLE 0x13 /*Load SS Init Data for Low Power Mode*/ +#define LOAD_CX_MS_KEY 0x14 /*Load MS Init Data for Key*/ +#define LOAD_CX_SS_KEY 0x15 /*Load SS Init Data for Key*/ +#define LOAD_CX_MS_FORCE 0x16 /*Load MS Init Data for Force*/ +#define LOAD_CX_SS_FORCE 0x17 /*Load SS Init Data for Force*/ +#define LOAD_CX_SS_HOVER 0x18 /*Load SS Hover Init Data for* Force */ +#define LOAD_SYNC_FRAME_RAW 0x30 /*Load a Synchronized Raw Frame*/ +#define LOAD_SYNC_FRAME_FILTER 0x31 /*Load a Synchronized Filter Frame*/ +#define LOAD_SYNC_FRAME_STRENGTH 0x33 /*Load a Synchronized Strength Frame*/ +#define LOAD_SYNC_FRAME_BASELINE 0x32 /*Load a Synchronized Baseline Frame*/ +#define LOAD_PANEL_CX_TOT_MS_TOUCH 0x50 /*Load TOT MS Init Data for Active Mode*/ +#define LOAD_PANEL_CX_TOT_MS_LOW_POWER 0x51 /*Load TOT MS Init Data for Low Power Mode*/ +#define LOAD_PANEL_CX_TOT_SS_TOUCH 0x52 /*Load TOT SS Init Data for Active Mode*/ +#define LOAD_PANEL_CX_TOT_SS_TOUCH_IDLE 0x53 /*Load TOT SS Init Data for Low Power Mode*/ +#define LOAD_PANEL_CX_TOT_MS_KEY 0x54 /*Load TOT MS Init Data for Key*/ +#define LOAD_PANEL_CX_TOT_SS_KEY 0x55 /*Load TOT SS Init Data for Key*/ +#define LOAD_PANEL_CX_TOT_MS_FORCE 0x56 /*Load TOT MS Init Data for Force*/ +#define LOAD_PANEL_CX_TOT_SS_FORCE 0x57 /*Load TOT SS Init Data for Force*/ +#define STAPI_HOST_DATA_ID_PANEL_CX_SS_HVR 0x58 /*Load HOVER TOT SS Init Data for Activity*/ + +/** @}*/ + +#define SPECIAL_TUNING_LP_TIMER 0x01 /*Perform LP Timer calibration*/ +#define SPECIAL_TUNING_IOFF 0x02 /*Perform Ioff calibration*/ + +/** @}*/ + +/** @defgroup events_group FW Event IDs and Types +* Event IDs and Types pushed by the FW into the FIFO +* @{ +*/ +#define EVT_ID_NOEVENT 0x00 /*No Events*/ +#define EVT_ID_CONTROLLER_READY 0x03 /*Controller ready, issued after a system reset.*/ +#define EVT_ID_ENTER_POINT 0x13 /*Touch enter in the sensing area*/ +#define EVT_ID_MOTION_POINT 0x23 /*Touch motion (a specific touch changed position)*/ +#define EVT_ID_LEAVE_POINT 0x33 /*Touch leave the sensing area*/ +#define EVT_ID_STATUS_UPDATE 0x43 /*FW report a system condition change*/ +#define EVT_ID_USER_REPORT 0x53 /*User related events triggered (keys, gestures, proximity etc)*/ +#define EVT_ID_DEBUG 0xE3 /*Debug Info*/ +#define EVT_ID_ERROR 0xF3 /*Error Event*/ + +#define NUM_EVT_ID (((EVT_ID_ERROR & 0xF0) >> 4) + 1) /*Max number of unique event IDs supported*/ +/** @}*/ + +/** @defgroup status_type Status Event Types +* @ingroup events_group +* Types of EVT_ID_STATUS_UPDATE events +* @{ +*/ +#define EVT_TYPE_STATUS_ECHO 0x01 /*Echo event, contain the first 5 bytes of the FW command sent*/ +#define EVT_TYPE_STATUS_FRAME_DROP 0x03 /*Some frame was skipped during the elaboration*/ +#define EVT_TYPE_STATUS_FORCE_CAL 0x05 /*Force Calibration has triggered*/ +#define EVT_TYPE_STATUS_WATER 0x06 /*Water Mode*/ +#define EVT_TYPE_STATUS_SS_RAW_SAT 0x07 /*Self Sense data saturated*/ +#define EVT_TYPE_STATUS_POCKET 0x09 +/** @} */ + +/** @defgroup user_type User Event Types +* @ingroup events_group +* Types of EVT_ID_USER_REPORT events generated by thw FW +* @{ +*/ +#define EVT_TYPE_USER_KEY 0x00 /*Keys pressed/relesed event report*/ +#define EVT_TYPE_USER_PROXIMITY 0x01 /*Proximity detection event report*/ +#define EVT_TYPE_USER_GESTURE 0x02 /*Gesture detection event report*/ +#define EVT_TYPE_USER_EARDET 0x03 /*ear detection event report*/ + +/** @}*/ + +/** @defgroup error_type Error Event Types +* @ingroup events_group +* Types of EVT_ID_ERROR events reported by the FW +* @{ +*/ +#define EVT_TYPE_ERROR_WATCHDOG 0x06 /*Watchdog timer expired*/ + +#define EVT_TYPE_ERROR_CRC_CFG_HEAD 0x20 /*CRC error in the Config Area Header*/ +#define EVT_TYPE_ERROR_CRC_CFG 0x21 /*CRC error in the Config Area*/ +#define EVT_TYPE_ERROR_CRC_PANEL_HEAD 0x22 /*CRC error in the Panel Area Header*/ +#define EVT_TYPE_ERROR_CRC_PANEL 0x23 /*CRC error in the Panel Area*/ + +#define EVT_TYPE_ERROR_ITO_FORCETOGND 0x60 /*Force channel/s short to ground*/ +#define EVT_TYPE_ERROR_ITO_SENSETOGND 0x61 /*Sense channel/s short to ground*/ +#define EVT_TYPE_ERROR_ITO_FORCETOVDD 0x62 /*Force channel/s short to VDD*/ +#define EVT_TYPE_ERROR_ITO_SENSETOVDD 0x63 /*Sense channel/s short to VDD*/ +#define EVT_TYPE_ERROR_ITO_FORCE_P2P 0x64 /*Pin to Pin short Force channel/s*/ +#define EVT_TYPE_ERROR_ITO_SENSE_P2P 0x65 /*Pin to Pin short Sense channel/s*/ +#define EVT_TYPE_ERROR_ITO_FORCEOPEN 0x66 /*Force Panel open*/ +#define EVT_TYPE_ERROR_ITO_SENSEOPEN 0x67 /*Sense Panel open*/ +#define EVT_TYPE_ERROR_ITO_KEYOPEN 0x68 /*Key open*/ + +#define EVT_TYPE_ERROR_CRC_CX_HEAD 0xA0 /*CRC error in the CX Area Header*/ +#define EVT_TYPE_ERROR_CRC_CX 0xA1 /*CRC error in the CX Area*/ +#define EVT_TYPE_ERROR_CRC_CX_SUB_HEAD 0xA5 /*CRC error in the CX Subsection Area Header*/ +#define EVT_TYPE_ERROR_CRC_CX_SUB 0xA6 /*CRC error in the CX Subsection Area*/ + +#define EVT_TYPE_ERROR_ESD 0xF0 /*ESD error*/ +/** @}*/ + +/** @defgroup address Chip Address + * Collection of HW and SW Addresses useful to collect different kind of data + * @{ + */ + +/** @defgroup config_adr SW Address + * @ingroup address + * Important addresses of data stored into Config memory (and sometimes their dimensions) + * @{ + */ +#define ADDR_CONFIG_ID 0x0010 /*Starting Address of the config ID*/ +#define CONFIG_ID_BYTE 2 /*Number of bytes of config ID*/ +#define ADDR_CONFIG_SENSE_LEN 0x0030 /*Address where is stored the number of sense channels*/ +#define ADDR_CONFIG_FORCE_LEN 0x0031 /*Address where is stored the number of force channels*/ +/** @}*/ + +/** @}*/ + +#define ERROR_DUMP_ROW_SIZE 32 /*number of rows of the error memory*/ +#define ERROR_DUMP_COL_SIZE 4 /*number of bytes for each row of the error memory*/ +#define ERROR_DUMP_SIGNATURE 0xFA5005AF /*first row signature of a proper dump*/ + +#define TOUCH_TYPE_INVALID 0x00 /*Invalid touch type*/ +#define TOUCH_TYPE_FINGER 0x01 /*Finger touch*/ +#define TOUCH_TYPE_GLOVE 0x02 /*Glove touch*/ +#define TOUCH_TYPE_STYLUS 0x03 /*Stylus touch*/ +#define TOUCH_TYPE_PALM 0x04 /*Palm touch*/ +#define TOUCH_TYPE_HOVER 0x05 /*Hovering touch*/ + +#define FTS_KEY_0 0x01 /*Key 0 bit*/ +#define FTS_KEY_1 0x02 /*Key 1 bit*/ +#define FTS_KEY_2 0x04 /*Key 2 bit*/ +#define FTS_KEY_3 0x08 /*Key 3 bit*/ +#define FTS_KEY_4 0x10 /*Key 4 bit*/ +#define FTS_KEY_5 0x20 /*Key 5 bit*/ +#define FTS_KEY_6 0x40 /*Key 6 bit*/ +#define FTS_KEY_7 0x80 /*Key 7 bit*/ + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsTest.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsTest.c new file mode 100644 index 000000000000..47c12c52dda9 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsTest.c @@ -0,0 +1,5936 @@ +/* + + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS API for MP test * + * * + ************************************************************************** + ************************************************************************** + + */ + +/*! + * \file ftsTest.c + * \brief Contains all the functions related to the Mass Production Test + */ + +#include "ftsCompensation.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsFrame.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTest.h" +#include "ftsTime.h" +#include "ftsTool.h" +#include "../fts.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef LIMITS_H_FILE +#include "../fts_limits.h" +#endif + +TestToDo tests; +static LimitFile limit_file; + +/** + * Initialize the testToDo variable with the default tests to perform during the Mass Production Test + * @return OK + */ +int initTestToDo(void) +{ + /*** Initialize Limit File ***/ + limit_file.size = 0; + limit_file.data = NULL; + strlcpy(limit_file.name, " ", MAX_LIMIT_FILE_NAME); + tests.SelfHoverForceRaw=1; /* /< SS Hover Force Raw min/Max test */ + tests.SelfHoverSenceRaw=1; /* /< SS Hover Sence Raw min/Max test */ + tests.SelfHoverForceIxTotal=1; /* /< SS Hover Total Force Ix min/Max (for each node)* test */ + tests.SelfHoverSenceIxTotal=1; + tests.MutualRawAdjITO = 0; + tests.MutualRaw = 0; + tests.MutualRawEachNode = 1; + tests.MutualRawGap = 0; + tests.MutualRawAdj = 0; + tests.MutualRawLP = 0; + tests.MutualRawGapLP = 0; + tests.MutualRawAdjLP = 0; + tests.MutualCx1 = 0; + tests.MutualCx2 = 0; + tests.MutualCx2Adj = 0; + tests.MutualCxTotal = 0; + tests.MutualCxTotalAdj = 0; + + tests.MutualCx1LP = 0; + tests.MutualCx2LP = 1; + tests.MutualCx2AdjLP = 1; + tests.MutualCxTotalLP = 0; + tests.MutualCxTotalAdjLP = 0; +#ifdef PHONE_KEY + tests.MutualKeyRaw = 0; +#else + tests.MutualKeyRaw = 0; +#endif + tests.MutualKeyCx1 = 0; + tests.MutualKeyCx2 = 0; +#ifdef PHONE_KEY + tests.MutualKeyCxTotal = 0; +#else + tests.MutualKeyCxTotal = 0; +#endif + tests.SelfForceRaw = 1; + tests.SelfForceRawGap = 0; + tests.SelfForceRawLP = 0; + tests.SelfForceRawGapLP = 0; + tests.SelfForceIx1 = 0; + tests.SelfForceIx2 = 0; + tests.SelfForceIx2Adj = 0; + tests.SelfForceIxTotal = 1; + tests.SelfForceIxTotalAdj = 0; + tests.SelfForceCx1 = 0; + tests.SelfForceCx2 = 0; + tests.SelfForceCx2Adj = 0; + tests.SelfForceCxTotal = 0; + tests.SelfForceCxTotalAdj = 0; + tests.SelfSenseRaw = 1; + tests.SelfSenseRawGap = 0; + tests.SelfSenseRawLP = 0; + tests.SelfSenseRawGapLP = 0; + tests.SelfSenseIx1 = 0; + tests.SelfSenseIx2 = 0; + tests.SelfSenseIx2Adj = 0; + tests.SelfSenseIxTotal = 1; + tests.SelfSenseIxTotalAdj = 0; + tests.SelfSenseCx1 = 0; + tests.SelfSenseCx2 = 0; + tests.SelfSenseCx2Adj = 0; + tests.SelfSenseCxTotal = 0; + tests.SelfSenseCxTotalAdj = 0; + return OK; +} + +/** + * Compute the Horizontal adjacent matrix doing the abs of the difference between the column i with the i-1 one. \n + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of signed bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjHoriz(i8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + logError(1, "%s computeAdjHoriz: ERROR % 08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *) kmalloc(size * sizeof(u8), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjHoriz: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 0; i < row; i++) { + for (j = 1; j < column; j++) { + *(*result + (i * (column - 1) + (j - 1))) = + abs(data[i * column + j] - + data[i * column + (j - 1)]); + } + } + + return OK; +} + +/** + * Compute the Horizontal adjacent matrix of short values doing the abs of the difference between the column i with the i-1 one. + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of signed bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjHorizTotal(short *data, int row, int column, u16 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + logError(1, "%s computeAdjHorizTotal: ERROR % 08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *) kmalloc(size * sizeof(u16), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjHorizTotal: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 0; i < row; i++) { + for (j = 1; j < column; j++) { + *(*result + (i * (column - 1) + (j - 1))) = + abs(data[i * column + j] - + data[i * column + (j - 1)]); + } + } + + return OK; +} + +/** + * Compute the Vertical adjacent matrix doing the abs of the difference between the row i with the i-1 one. + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other. \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of signed bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjVert(i8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + logError(1, "%s computeAdjVert: ERROR % 08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *) kmalloc(size * sizeof(u8), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjVert: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 1; i < row; i++) { + for (j = 0; j < column; j++) { + *(*result + ((i - 1) * column + j)) = + abs(data[i * column + j] - + data[(i - 1) * column + j]); + } + } + + return OK; +} + +/** + * Compute the Vertical adjacent matrix of short values doing the abs of the difference between the row i with the i-1 one. + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other. \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of signed bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjVertTotal(short *data, int row, int column, u16 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + logError(1, "%s computeAdjVertTotal: ERROR %08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *) kmalloc(size * sizeof(u16), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjVertTotal: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 1; i < row; i++) { + for (j = 0; j < column; j++) { + *(*result + ((i - 1) * column + j)) = + abs(data[i * column + j] - + data[(i - 1) * column + j]); + } + } + + return OK; +} + +/** + * Compute the Horizontal adjacent matrix doing the abs of the difference between the column i with the i-1 one. \n + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of unsigned bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjHorizFromU(u8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + logError(1, "%s computeAdjHoriz: ERROR %08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *) kmalloc(size * sizeof(u8), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjHoriz: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 0; i < row; i++) { + for (j = 1; j < column; j++) { + *(*result + (i * (column - 1) + (j - 1))) = + abs(data[i * column + j] - + data[i * column + (j - 1)]); + } + } + + return OK; +} + +/** + * Compute the Horizontal adjacent matrix of u16 values doing the abs of the difference between the column i with the i-1 one. + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of unsigned bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjHorizTotalFromU(u16 *data, int row, int column, u16 **result) +{ + int i, j; + int size = row * (column - 1); + + if (column < 2) { + logError(1, "%s computeAdjHorizTotal: ERROR %08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *) kmalloc(size * sizeof(u16), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjHorizTotal: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 0; i < row; i++) { + for (j = 1; j < column; j++) { + *(*result + (i * (column - 1) + (j - 1))) = + abs(data[i * column + j] - + data[i * column + (j - 1)]); + } + } + + return OK; +} + +/** + * Compute the Vertical adjacent matrix doing the abs of the difference between the row i with the i-1 one. + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other. \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of unsigned bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjVertFromU(u8 *data, int row, int column, u8 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + logError(1, "%s computeAdjVert: ERROR %08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u8 *) kmalloc(size * sizeof(u8), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjVert: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 1; i < row; i++) { + for (j = 0; j < column; j++) { + *(*result + ((i - 1) * column + j)) = + abs(data[i * column + j] - + data[(i - 1) * column + j]); + } + } + + return OK; +} + +/** + * Compute the Vertical adjacent matrix of u16 values doing the abs of the difference between the row i with the i-1 one. + * Both the original data matrix and the adj matrix are disposed as 1 dimension array one row after the other. \n + * The resulting matrix has one column less than the starting original one \n + * @param data pointer to the array of unsigned bytes containing the original data + * @param row number of rows of the original data + * @param column number of columns of the original data + * @param result pointer of a pointer to an array of unsigned bytes which will contain the adj matrix + * @return OK if success or an error code which specify the type of error encountered + */ +int computeAdjVertTotalFromU(u16 *data, int row, int column, u16 **result) +{ + int i, j; + int size = (row - 1) * (column); + + if (row < 2) { + logError(1, "%s computeAdjVertTotal: ERROR %08X\n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + *result = (u16 *) kmalloc(size * sizeof(u16), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeAdjVertTotal: ERROR %08X\n", tag, + ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 1; i < row; i++) { + for (j = 0; j < column; j++) { + *(*result + ((i - 1) * column + j)) = + abs(data[i * column + j] - + data[(i - 1) * column + j]); + } + } + + return OK; +} + +int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, + u16 **result) +{ + int i, j; + int size = (row) * (column); + *result = (u16 *) kmalloc(size * sizeof(u16), GFP_KERNEL); + + if (*result == NULL) { + logError(1, "%s computeTotal : ERROR %02X\n", tag, ERROR_ALLOC); + return ERROR_ALLOC; + } + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + *(*result + (i * column + j)) = + m * main + n * data[i * column + j]; + } + } + + return OK; +} + +/** + * Check that each value of a matrix of short doesn't exceed a min and a Max value (these values are included in the interval). \n + * The matrix is stored as 1 dimension array one row after the other. \n + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param min minimum value allowed + * @param max Maximum value allowed + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMinMax(short *data, int row, int column, int min, int max) +{ + int i, j; + int count = 0; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] < min + || data[i * column + j] > max) { + logError(1, + "%s checkLimitsMinMax: Node[%d,%d] = %d exceed limit [%d, %d] \n", + tag, i, j, data[i * column + j], min, + max); + count++; + } + } + } + + return count; +} + +/** + * Check that the difference between the max and min of a matrix of short is less or equal to a threshold.\n + * The matrix is stored as 1 dimension array one row after the other. + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param threshold threshold value allowed + * @return OK if the difference is <= to threshold otherwise ERROR_TEST_CHECK_FAIL + */ +int checkLimitsGap(short *data, int row, int column, int threshold) +{ + int i, j; + int min_node; + int max_node; + + if (row == 0 || column == 0) { + logError(1, + "%s checkLimitsGap: invalid number of rows = %d or columns = %d ERROR %08X\n", + tag, row, column, ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } + + min_node = data[0]; + max_node = data[0]; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] < min_node) { + min_node = data[i * column + j]; + } else { + if (data[i * column + j] > max_node) + max_node = data[i * column + j]; + } + } + } + + if (max_node - min_node > threshold) { + logError(1, "%s checkLimitsGap: GAP = %d exceed limit %d \n", + tag, max_node - min_node, threshold); + return ERROR_TEST_CHECK_FAIL; + } else + return OK; +} + +/** + * Check that each value of a matrix of i8 doesn't exceed a specific min and Max value set for each node (these values are included in the interval). \n + * The matrixes of data, min and max values are stored as 1 dimension arrays one row after the other. + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param min pointer to a matrix which specify the minimum value allowed for each node + * @param max pointer to a matrix which specify the Maximum value allowed for each node + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMap(i8 *data, int row, int column, int *min, int *max) +{ + int i, j; + int count = 0; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] < min[i * column + j] + || data[i * column + j] > max[i * column + j]) { + logError(1, + "%s checkLimitsMap: Node[%d,%d] = %d exceed limit [%d, %d] \n", + tag, i, j, data[i * column + j], + min[i * column + j], + max[i * column + j]); + count++; + } + } + } + + return count; +} + +/** + * Check that each value of a matrix of short doesn't exceed a specific min and Max value set for each node (these values are included in the interval). + * The matrixes of data, min and max values are stored as 1 dimension arrays one row after the other. + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param min pointer to a matrix which specify the minimum value allowed for each node + * @param max pointer to a matrix which specify the Maximum value allowed for each node + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMapTotal(short *data, int row, int column, int *min, int *max) +{ + int i, j; + int count = 0; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] < min[i * column + j] + || data[i * column + j] > max[i * column + j]) { + logError(1, + "%s checkLimitsMapTotal: Node[%d,%d] = %d exceed limit [%d, %d] \n", + tag, i, j, data[i * column + j], + min[i * column + j], + max[i * column + j]); + count++; + } + } + } + + return count; +} + +/** + * Check that each value of a matrix of u8 doesn't exceed a specific min and Max value set for each node (these values are included in the interval). \n + * The matrixes of data, min and max values are stored as 1 dimension arrays one row after the other. + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param min pointer to a matrix which specify the minimum value allowed for each node + * @param max pointer to a matrix which specify the Maximum value allowed for each node + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMapFromU(u8 *data, int row, int column, int *min, int *max) +{ + int i, j; + int count = 0; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] < min[i * column + j] + || data[i * column + j] > max[i * column + j]) { + logError(1, + "%s checkLimitsMap: Node[%d,%d] = %d exceed limit [%d, %d] \n", + tag, i, j, data[i * column + j], + min[i * column + j], + max[i * column + j]); + count++; + } + } + } + + return count; +} + +/** + * Check that each value of a matrix of u16 doesn't exceed a specific min and Max value set for each node (these values are included in the interval). + * The matrixes of data, min and max values are stored as 1 dimension arrays one row after the other. + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param min pointer to a matrix which specify the minimum value allowed for each node + * @param max pointer to a matrix which specify the Maximum value allowed for each node + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMapTotalFromU(u16 *data, int row, int column, int *min, + int *max) +{ + int i, j; + int count = 0; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] < min[i * column + j] + || data[i * column + j] > max[i * column + j]) { + logError(1, + "%s checkLimitsMapTotal: Node[%d,%d] = %d exceed limit [%d, %d] \n", + tag, i, j, data[i * column + j], + min[i * column + j], + max[i * column + j]); + count++; + } + logError(1, + "%s checkLimitsMapTotal: Node[%d,%d] = %d\n", + tag, i, j, data[i * column + j], + min[i * column + j], + max[i * column + j]); + } + } + + return count; +} + +/** + * Check that each value of a matrix of u8 doesn't exceed a specific Max value set for each node (max value is included in the interval). + * The matrixes of data and max values are stored as 1 dimension arrays one row after the other. + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param max pointer to a matrix which specify the Maximum value allowed for each node + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMapAdj(u8 *data, int row, int column, int *max) +{ + int i, j; + int count = 0; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] > max[i * column + j]) { + logError(1, + "%s checkLimitsMapAdj: Node[%d,%d] = %d exceed limit > %d \n", + tag, i, j, data[i * column + j], + max[i * column + j]); + count++; + } + } + } + + return count; +} + +/** + * Check that each value of a matrix of u16 doesn't exceed a specific Max value set for each node (max value is included in the interval). + * The matrixes of data and max values are stored as 1 dimension arrays one row after the other. + * @param data pointer to the array of short containing the data to check + * @param row number of rows of data + * @param column number of columns of data + * @param max pointer to a matrix which specify the Maximum value allowed for each node + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max) +{ + int i, j; + int count = 0; + + for (i = 0; i < row; i++) { + for (j = 0; j < column; j++) { + if (data[i * column + j] > max[i * column + j]) { + logError(1, + "%s checkLimitsMapAdjTotal: Node[%d,%d] = %d exceed limit > %d \n", + tag, i, j, data[i * column + j], + max[i * column + j]); + count++; + } + } + } + + return count; +} + +/** + * Perform an ITO test setting all the possible options (see @link ito_opt ITO Options @endlink) + * @return the number of elements that overcome the specified interval (0 = OK) + */ +int production_test_ito(char *path_limits, TestToDo *todo) +{ + int res = OK; + u8 sett[2] = { 0x00, 0x00 }; + MutualSenseFrame msRawFrame; + int *thresholds = NULL; + u16 *adj = NULL; + int trows, tcolumns; + logError(1, "%s ITO Production test is starting...\n", tag); + memset(&msRawFrame, 0x00, sizeof(msRawFrame)); + res = fts_system_reset(); + + if (res < 0) { + logError(1, "%s %s: ERROR %08X \n", tag, __func__, + ERROR_PROD_TEST_ITO); + return (res | ERROR_PROD_TEST_ITO); + } + + sett[0] = SPECIAL_TUNING_IOFF; + logError(0, "%s Trimming Ioff... \n", tag); + res = writeSysCmd(SYS_CMD_SPECIAL_TUNING, sett, 2); + + if (res < OK) { + logError(1, "%s production_test_ito: Trimm Ioff ERROR %08X \n", + tag, (res | ERROR_PROD_TEST_ITO)); + return (res | ERROR_PROD_TEST_ITO); + } + + sett[0] = 0xFF; + sett[1] = 0xFF; + logError(0, "%s ITO Check command sent... \n", tag); + res = writeSysCmd(SYS_CMD_ITO, sett, 2); + + if (res < OK) { + logError(1, "%s production_test_ito: ERROR %08X \n", tag, + (res | ERROR_PROD_TEST_ITO)); + return (res | ERROR_PROD_TEST_ITO); + } + + logError(0, "%s ITO Command = OK! \n", tag); + + if (todo->MutualRawAdjITO == 1) { + logError(1, "%s MS RAW ITO ADJ TEST: \n", tag); + logError(0, "%s Collecting MS Raw data... \n", tag); + res |= getMSFrame3(MS_RAW, &msRawFrame); + + if (res < OK) { + logError(1, "%s %s: getMSFrame failed... ERROR %08X \n", + tag, __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + logError(0, "%s MS RAW ITO ADJ HORIZONTAL TEST: \n", tag); + res = + computeAdjHorizTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, &adj); + + if (res < OK) { + logError(1, + "%s %s: computeAdjHoriz failed... ERROR %08X \n", + tag, __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + res = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_ITO_ADJH, &thresholds, + &trows, &tcolumns); + + if (res < OK + || (trows != msRawFrame.header.force_node + || tcolumns != msRawFrame.header.sense_node - 1)) { + logError(1, + "%s %s: parseProductionTestLimits MS_RAW_ITO_ADJH failed... ERROR %08X \n", + tag, __func__, ERROR_PROD_TEST_DATA); + goto ERROR; + } + + res = + checkLimitsMapAdjTotal(adj, msRawFrame.header.force_node, + msRawFrame.header.sense_node - 1, + thresholds); + + if (res != OK) { + logError(1, + "%s production_test_data: checkLimitsAdj MS RAW ITO ADJH failed... ERROR COUNT = %d \n", + tag, res); + logError(0, + "%s MS RAW ITO ADJ HORIZONTAL TEST:.................FAIL \n\n", + tag); + print_frame_short("MS Raw ITO frame =", + array1dTo2d_short + (msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + res = ERROR_PROD_TEST_ITO; + goto ERROR; + } else + logError(0, + "%s MS RAW ITO ADJ HORIZONTAL TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + kfree(adj); + adj = NULL; + logError(0, "%s MS RAW ITO ADJ VERTICAL TEST: \n", tag); + res = + computeAdjVertTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, &adj); + + if (res < OK) { + logError(1, + "%s %s: computeAdjVert failed... ERROR %08X \n", + tag, __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + res = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_ITO_ADJV, &thresholds, + &trows, &tcolumns); + + if (res < OK + || (trows != msRawFrame.header.force_node - 1 + || tcolumns != msRawFrame.header.sense_node)) { + logError(1, + "%s %s: parseProductionTestLimits MS_RAW_ITO_ADJV failed... ERROR %08X \n", + tag, __func__, ERROR_PROD_TEST_ITO); + goto ERROR; + } + + res = + checkLimitsMapAdjTotal(adj, + msRawFrame.header.force_node - 1, + msRawFrame.header.sense_node, + thresholds); + + if (res != OK) { + logError(1, + "%s %s: checkLimitsAdj MS RAW ITO ADJV failed... ERROR COUNT = %d \n", + tag, __func__, res); + logError(0, + "%s MS RAW ITO ADJ VERTICAL TEST:.................FAIL \n\n", + tag); + print_frame_short("MS Raw ITO frame =", + array1dTo2d_short + (msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + res = ERROR_PROD_TEST_ITO; + goto ERROR; + } else + logError(0, + "%s MS RAW ITO ADJ VERTICAL TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + kfree(adj); + adj = NULL; + } else + logError(0, + "%s MS RAW ITO ADJ TEST:.................SKIPPED \n", + tag); + +ERROR: + + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (adj != NULL) { + kfree(adj); + adj = NULL; + } + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + freeLimitsFile(&limit_file); + res |= fts_system_reset(); + + if (res < OK) { + logError(1, "%s production_test_ito: ERROR %08X \n", tag, + ERROR_PROD_TEST_ITO); + res = (res | ERROR_PROD_TEST_ITO); + } + + return res; +} + +/** + * Perform the Initialization of the IC + * @param type type of initialization to do (see @link sys_special_opt Initialization Options (Full or Panel) @endlink) + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_initialization(u8 type) +{ + int res; + logError(1, "%s INITIALIZATION Production test is starting,type:%d\n", tag, type); + + if (type != SPECIAL_PANEL_INIT && type != SPECIAL_FULL_PANEL_INIT) { + logError(1, + "%s production_test_initialization: Type incompatible! Type = %02X ERROR %08X \n", + tag, type, + ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_INITIALIZATION); + return (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_INITIALIZATION); + } + + res = fts_system_reset(); + + if (res < 0) { + logError(1, "%s production_test_initialization: ERROR %08X \n", + tag, ERROR_PROD_TEST_INITIALIZATION); + return (res | ERROR_PROD_TEST_INITIALIZATION); + } + + logError(0, "%s INITIALIZATION command sent... %02X \n", tag, type); + res = writeSysCmd(SYS_CMD_SPECIAL, &type, 1); + + if (res < OK) { + logError(1, "%s production_test_initialization: ERROR %08X \n", + tag, (res | ERROR_PROD_TEST_INITIALIZATION)); + return (res | ERROR_PROD_TEST_INITIALIZATION); + } + + logError(0, "%s Refresh Sys Info...\n", tag); + res |= readSysInfo(1); + + if (res < 0) { + logError(1, + "%s production_test_initialization: read sys info ERROR %08X\n", + tag, ERROR_PROD_TEST_INITIALIZATION); + res = (res | ERROR_PROD_TEST_INITIALIZATION); + } + + return res; +} + +/** + * Perform a FULL (ITO + INIT + DATA CHECK) Mass Production Test of the IC + * @param pathThresholds name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param saveInit if >0 (possible values: NO_INIT, SPECIAL_PANEL_INIT or SPECIAL_FULL_PANEL_INIT), the Initialization of the IC is executed otherwise it is skipped + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_main(char *pathThresholds, int stop_on_fail, int saveInit, + TestToDo *todo) +{ + int res, ret; + logError(0, "%s MAIN Production test is starting...\n", tag); + logError(0, "%s \n", tag); + logError(0, "%s ITO TEST: \n", tag); + res = production_test_ito(pathThresholds, todo); + + if (res < 0) { + logError(0, "%s Error during ITO TEST! ERROR %08X\n", tag, res); + goto END; + } else { + logError(0, "%s ITO TEST OK!\n", tag); + } + + logError(0, "%s \n", tag); + logError(0, "%s INITIALIZATION TEST : \n", tag); + + if (saveInit != NO_INIT) { + res = production_test_initialization((u8) saveInit); + + if (res < 0) { + logError(0, + "%s Error during INITIALIZATION TEST! ERROR %08X\n", + tag, res); + + if (stop_on_fail) + goto END; + } else { + logError(0, "%s INITIALIZATION TEST OK!\n", tag); + } + } else + logError(0, + "%s INITIALIZATION TEST :................. SKIPPED \n", + tag); + + logError(0, "%s \n", tag); + + if (saveInit == 1) { + logError(0, "%s Cleaning up...\n", tag); + ret = fts_system_reset(); + + if (ret < 0) { + logError(1, + "%s production_test_main: system reset ERROR %08X\n", + tag, ret); + res |= ret; + + if (stop_on_fail) + goto END; + } + + logError(0, "%s \n", tag); + } + + logError(1, "%s PRODUCTION DATA TEST: \n", tag); + ret = production_test_data(pathThresholds, stop_on_fail, todo); + + if (ret < 0) { + logError(0, + "%s Error during PRODUCTION DATA TEST! ERROR %08X\n", + tag, ret); + } else { + logError(0, "%s PRODUCTION DATA TEST OK!\n", tag); + } + + res |= ret; +END: + + if (res < 0) { + logError(0, + "%s MAIN Production test finished.................FAILED \n", + tag); + return res; + } else { + logError(0, + "%s MAIN Production test finished.................OK\n", + tag); + return OK; + } +} + +/** + * Perform all the test selected in a TestTodo variable related to MS raw data (touch, keys etc..) + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int ret, count_fail = 0; + MutualSenseFrame msRawFrame; + int *thresholds = NULL; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + int trows, tcolumns; + u16 *adj = NULL; + /******************************* Mutual Sense Test *******************************/ + logError(0, "%s \n", tag); + + if (todo->MutualRaw == 1 || todo->MutualRawGap == 1 + || todo->MutualRawAdj == 1 || todo->MutualRawEachNode == 1) { + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_ACTIVE); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getMSFrame3(MS_RAW, &msRawFrame); + + if (ret < OK) { + logError(1, + "%s production_test_data: getMSFrame failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + + if (todo->MutualRaw == 1) { + logError(1, "%s MS RAW MIN MAX TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_MIN_MAX, + &thresholds, &trows, + &tcolumns); + + if (ret < OK || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0], thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax MS RAW failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS RAW MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW MIN MAX TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s MS RAW MIN MAX TEST:.................SKIPPED \n", + tag); + if (todo->MutualRawEachNode == 1) { + logError(1, "%s MS RAW EACH NODE MIN MAX TEST:\n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, MS_RAW_EACH_NODE_MIN, &thresholds_min, &trows, &tcolumns); + if (ret < OK || (trows != msRawFrame.header.force_node || tcolumns != msRawFrame.header.sense_node)) { + logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_EACH_NODE_MIN failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + ret = parseProductionTestLimits(path_limits, &limit_file, MS_RAW_EACH_NODE_MAX, &thresholds_max, &trows, &tcolumns); + if (ret < OK || (trows != msRawFrame.header.force_node || + tcolumns != msRawFrame.header.sense_node)) { + logError(1, "%s production_test_data: parseProductionTestLimits MS_RAW_EACH_NODE_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + ret = checkLimitsMapTotal(msRawFrame.node_data, msRawFrame.header.force_node, msRawFrame.header.sense_node, thresholds_min, thresholds_max); + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMaxEachNodeData failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s MS_RAW EACH NODE MIN MAX TEST:.................FAIL\n\n", tag); + count_fail += 1; + if (stop_on_fail == 1) + goto ERROR; + } else { + logError(0, "%s MS_RAW_EACH_NODE_MAX TEST:.................OK\n", tag); + } + if (thresholds_min != NULL) { + kfree(thresholds_min); + thresholds_min = NULL; + } + if (thresholds_max != NULL) { + kfree(thresholds_max); + thresholds_max = NULL; + } + } else { + logError(0, "%s MS RAW EACH NODE MIN MAX TEST:.................SKIPPED\n", tag); + } + + logError(0, "%s \n", tag); + + if (todo->MutualRawGap == 1) { + logError(1, "%s MS RAW GAP TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_GAP, &thresholds, + &trows, &tcolumns); + + if (ret < OK || (trows != 1 || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_GAP failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsGap(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsGap MS RAW failed... ERROR = %08X \n", + tag, ret); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW GAP TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s MS RAW GAP TEST:.................SKIPPED \n", + tag); + + logError(0, "%s \n", tag); + + if (todo->MutualRawAdj == 1) { + logError(1, "%s MS RAW ADJ HORIZONTAL TEST: \n", tag); + ret = + computeAdjHorizTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + + if (ret < OK) { + logError(1, + "%s production_test_data: computeAdjHoriz failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_ADJH, &thresholds, + &trows, &tcolumns); + + if (ret < OK + || (trows != msRawFrame.header.force_node + || tcolumns != + msRawFrame.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_ADJH failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdjTotal(adj, + msRawFrame.header.force_node, + msRawFrame.header. + sense_node - 1, thresholds); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsAdj MS RAW ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS RAW ADJ HORIZONTAL TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW ADJ HORIZONTAL TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + kfree(adj); + adj = NULL; + logError(0, "%s MS RAW ADJ VERTICAL TEST: \n", tag); + ret = + computeAdjVertTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + + if (ret < OK) { + logError(1, + "%s production_test_data: computeAdjVert failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_ADJV, &thresholds, + &trows, &tcolumns); + + if (ret < OK + || (trows != msRawFrame.header.force_node - 1 + || tcolumns != msRawFrame.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_ADJV failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdjTotal(adj, + msRawFrame.header. + force_node - 1, + msRawFrame.header.sense_node, + thresholds); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsAdj MS RAW ADJV failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS RAW ADJ VERTICAL TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW ADJ VERTICAL TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + kfree(adj); + adj = NULL; + } else + logError(0, + "%s MS RAW ADJ TEST:.................SKIPPED \n", + tag); + } else + logError(0, "%s MS RAW FRAME TEST:.................SKIPPED \n", + tag); + + logError(0, "%s \n", tag); + + if (todo->MutualKeyRaw == 1) { + logError(1, "%s MS KEY RAW TEST:\n", tag); + ret = production_test_ms_key_raw(path_limits); + + if (ret < 0) { + logError(1, + "%s production_test_data: production_test_ms_key_raw failed... ERROR = %08X \n", + tag, ret); + count_fail += 1; + + if (count_fail == 1) { + logError(0, + "%s MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", + tag, count_fail); + goto ERROR_LIMITS; + } + } + } else + logError(0, "%s MS KEY RAW TEST:.................SKIPPED \n", + tag); + + ret = production_test_ms_raw_lp(path_limits, stop_on_fail, todo); + + if (ret < 0) { + logError(1, + "%s production_test_data: production_test_ms_raw_lp failed... ERROR = %08X \n", + tag, ret); + count_fail += 1; + + if (count_fail == 1) { + logError(0, + "%s MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", + tag, count_fail); + goto ERROR_LIMITS; + } + } + +ERROR: + logError(0, "%s \n", tag); + + if (count_fail == 0) { + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + + logError(0, + "%s MS RAW DATA TEST finished!.................OK\n", + tag); + return OK; + } else { + print_frame_short("MS Raw frame =", + array1dTo2d_short(msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header. + sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (adj != NULL) { + kfree(adj); + adj = NULL; + } + logError(0, + "%s MS RAW DATA TEST:.................FAIL fails_count = %d\n\n", + tag, count_fail); + return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); + } + +ERROR_LIMITS: + + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + return ret; +} + +/** + * Perform all the test selected in a TestTodo variable related to MS low power raw data + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ms_raw_lp(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret, count_fail = 0; + MutualSenseFrame msRawFrame; + int *thresholds = NULL; + int trows, tcolumns; + u16 *adj = NULL; + memset(&msRawFrame, 0x00, sizeof(msRawFrame)); + /******************************* Mutual Sense Test *******************************/ + logError(0, "%s \n", tag); + + if (todo->MutualRawLP == 1 || todo->MutualRawGapLP == 1 + || todo->MutualRawAdjLP == 1) { + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_LP_ACTIVE); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getMSFrame3(MS_RAW, &msRawFrame); + + if (ret < 0) { + logError(1, + "%s production_test_data: getMSFrame failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + + if (todo->MutualRawLP == 1) { + logError(1, "%s MS RAW LP MIN MAX TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_LP_MIN_MAX, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_LP_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0], thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax MS RAW LP failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS RAW LP MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW LP MIN MAX TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s MS RAW LP MIN MAX TEST:.................SKIPPED \n", + tag); + + logError(0, "%s \n", tag); + + if (todo->MutualRawGapLP == 1) { + logError(1, "%s MS RAW LP GAP TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_LP_GAP, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_LP_GAP failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsGap(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + thresholds[0]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsGap MS RAW LP failed... ERROR = %08X \n", + tag, ret); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW LP GAP TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s MS RAW LP GAP TEST:.................SKIPPED \n", + tag); + + logError(0, "%s \n", tag); + + if (todo->MutualRawAdjLP == 1) { + logError(1, "%s MS RAW LP ADJ HORIZONTAL TEST: \n", + tag); + ret = + computeAdjHorizTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_LP_ADJH, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 + || (trows != msRawFrame.header.force_node + || tcolumns != + msRawFrame.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_LP_ADJH failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdjTotal(adj, + msRawFrame.header.force_node, + msRawFrame.header. + sense_node - 1, thresholds); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsAdj MS RAW LP ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS RAW LP ADJ HORIZONTAL TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW LP ADJ HORIZONTAL TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + kfree(adj); + adj = NULL; + logError(0, "%s MS RAW LP ADJ VERTICAL TEST: \n", tag); + ret = + computeAdjVertTotal(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, + &adj); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_RAW_LP_ADJV, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 + || (trows != msRawFrame.header.force_node - 1 + || tcolumns != msRawFrame.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_RAW_ADJV failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdjTotal(adj, + msRawFrame.header. + force_node - 1, + msRawFrame.header.sense_node, + thresholds); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsAdj MS RAW ADJV failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS RAW LP ADJ VERTICAL TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail == 1) + goto ERROR; + } else + logError(0, + "%s MS RAW LP ADJ VERTICAL TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + kfree(adj); + adj = NULL; + } else + logError(0, + "%s MS RAW LP ADJ TEST:.................SKIPPED \n", + tag); + } else + logError(0, + "%s MS RAW LP FRAME TEST:.................SKIPPED \n", + tag); + +ERROR: + logError(0, "%s \n", tag); + + if (count_fail == 0) { + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + + logError(0, + "%s MS RAW DATA TEST finished!.................OK\n", + tag); + return OK; + } else { + if (msRawFrame.node_data != NULL) { + print_frame_short("MS Raw LP frame =", + array1dTo2d_short + (msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (adj != NULL) { + kfree(adj); + adj = NULL; + } + logError(0, + "%s MS RAW LP DATA TEST:.................FAIL fails_count = %d\n\n", + tag, count_fail); + return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); + } + +ERROR_LIMITS: + + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + return ret; +} + +/** + * Perform MS raw test for keys data + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ms_key_raw(char *path_limits) +{ + int ret; + MutualSenseFrame msRawFrame; + int *thresholds = NULL; + int trows, tcolumns; + /******************************* Mutual Sense Test *******************************/ + logError(1, "%s MS KEY RAW DATA TEST is starting...\n", tag); + ret = setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getMSFrame3(MS_KEY_RAW, &msRawFrame); + + if (ret < 0) { + logError(1, + "%s production_test_data: getMSKeyFrame failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_RAW_MIN_MAX, &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_KEY_RAW_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMinMax(msRawFrame.node_data, + msRawFrame.header.force_node, + msRawFrame.header.sense_node, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax MS KEY RAW failed... ERROR COUNT = %d \n", + tag, ret); + goto ERROR; + } else + logError(0, "%s MS KEY RAW TEST:.................OK \n\n", tag); + + kfree(thresholds); + thresholds = NULL; + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + return OK; +ERROR: + print_frame_short("MS Key Raw frame =", + array1dTo2d_short(msRawFrame.node_data, + msRawFrame.node_data_size, + msRawFrame.header.sense_node), + msRawFrame.header.force_node, + msRawFrame.header.sense_node); + + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + logError(0, "%s MS KEY RAW TEST:.................FAIL \n\n", tag); + return (ERROR_PROD_TEST_DATA | ERROR_TEST_CHECK_FAIL); +ERROR_LIMITS: + + if (msRawFrame.node_data != NULL) { + kfree(msRawFrame.node_data); + msRawFrame.node_data = NULL; + } + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + return ret; +} + +/** + * Perform all the tests selected in a TestTodo variable related to MS Init data (touch, keys etc..) + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int ret; + int count_fail = 0; + int *thresholds = NULL; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + int trows, tcolumns; + MutualSenseData msCompData; + TotMutualSenseData totCompData; + u8 *adjhor = NULL; + u8 *adjvert = NULL; + u16 container; + u16 *total_adjhor = NULL; + u16 *total_adjvert = NULL; + logError(0, "%s \n", tag); + ret = readMutualSenseCompensationData(LOAD_CX_MS_TOUCH, &msCompData); + + if (ret < 0) { + logError(1, + "%s production_test_data: readMutualSenseCompensationData failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + ret = + readTotMutualSenseCompensationData(LOAD_PANEL_CX_TOT_MS_TOUCH, + &totCompData); + + if (ret < 0) { + logError(1, + "%s production_test_data: readTotMutualSenseCompensationData failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return (ret | ERROR_PROD_TEST_DATA); + } + + + if (todo->MutualCx1 == 1) { + logError(1, "%s MS CX1 TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_CX1_MIN_MAX, &thresholds, + &trows, &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX1_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (u16) msCompData.cx1; + ret = + checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, "%s MS CX1 TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, "%s MS CX1 TEST:.................OK \n\n", + tag); + } else + logError(0, "%s MS CX1 TEST:.................SKIPPED \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + + if (todo->MutualCx2 == 1) { + logError(1, "%s MS CX2 MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, MS_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, MS_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap MS CX2 MIN MAX failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS CX2 MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS CX2 MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s MS CX2 MIN MAX TEST:.................SKIPPED \n\n", + tag); + + + if (todo->MutualCx2Adj == 1) { + logError(1, "%s MS CX2 ADJ TEST: \n", tag); + ret = + computeAdjHoriz(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, &adjhor); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s MS CX2 ADJ HORIZ computed! \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + + if (ret < 0 + || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_ADJH_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdj(adjhor, msCompData.header.force_node, + msCompData.header.sense_node - 1, + thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj CX2 ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS CX2 ADJ HORIZ TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS CX2 ADJ HORIZ TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjhor); + adjhor = NULL; + logError(0, "%s MS CX2 ADJ VERT TEST: \n", tag); + ret = + computeAdjVert(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, &adjvert); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s MS CX2 ADJ VERT computed! \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + + if (ret < 0 + || (trows != msCompData.header.force_node - 1 + || tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_ADJV_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdj(adjvert, msCompData.header.force_node - 1, + msCompData.header.sense_node - 1, + thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj CX2 ADJV failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS CX2 ADJ HORIZ TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS CX2 ADJ VERT TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjvert); + adjvert = NULL; + } else + logError(0, "%s MS CX2 ADJ TEST:.................SKIPPED \n\n", + tag); + + + if (todo->MutualCxTotal == 1 || todo->MutualCxTotalAdj == 1) { + + if (todo->MutualCxTotal == 1) { + logError(1, "%s MS TOTAL CX MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, MS_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, MS_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.node_data, totCompData.header.force_node, totCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap MS TOTAL CX TEST failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS TOTAL CX MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS TOTAL CX MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s MS TOTAL CX MIN MAX TEST:.................SKIPPED \n\n", + tag); + + + if (todo->MutualCxTotalAdj == 1) { + logError(1, "%s MS TOTAL CX ADJ HORIZ TEST: \n", tag); + ret = + computeAdjHorizTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + &total_adjhor); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s MS TOTAL CX ADJ HORIZ computed! \n", + tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_TOTAL_CX_ADJH_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != + totCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJH_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdjTotal(total_adjhor, + totCompData.header. + force_node, + totCompData.header. + sense_node - 1, + thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS TOTAL CX ADJ HORIZ TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjhor); + total_adjhor = NULL; + logError(0, "%s MS TOTAL CX ADJ VERT TEST: \n", tag); + ret = + computeAdjVertTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + &total_adjvert); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s MS TOTAL CX ADJ VERT computed! \n", + tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_TOTAL_CX_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node - 1 + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJV_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdjTotal(total_adjvert, + totCompData.header. + force_node - 1, + totCompData.header. + sense_node - 1, + thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJV failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS TOTAL CX ADJ HORIZ TEST:.................FAIL \n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS TOTAL CX ADJ VERT TEST:.................OK \n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjvert); + total_adjvert = NULL; + } else + logError(0, + "%s MS TOTAL CX ADJ TEST:.................SKIPPED \n", + tag); + + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } else + logError(0, "%s MS TOTAL CX TEST:.................SKIPPED \n", + tag); + + if ((todo->MutualCx1LP | todo->MutualCx2LP | todo->MutualCx2AdjLP | + todo->MutualCxTotalLP | todo->MutualCxTotalAdjLP) == 1) { + ret = production_test_ms_cx_lp(path_limits, stop_on_fail, todo); + if (ret < OK) { + count_fail += 1; + logError(1, + "%s production_test_data: production_test_cx_lp failed... ERROR = %08X\n", + tag, ret); + logError(0, + "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + return ret; + } + } else + logError(0, "%s MS KEY CX TEST:.................SKIPPED\n", + tag); + + if ((todo->MutualKeyCx1 | + todo->MutualKeyCx2 | todo->MutualKeyCxTotal) == 1) { + ret = + production_test_ms_key_cx(path_limits, stop_on_fail, todo); + + if (ret < 0) { + count_fail += 1; + logError(1, + "%s production_test_data: production_test_ms_key_cx failed... ERROR = %08X \n", + tag, ret); + logError(0, + "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + return ret; + } + } else + logError(0, "%s MS KEY CX TEST:.................SKIPPED \n", + tag); + +ERROR: + logError(0, "%s \n", tag); + + if (count_fail == 0) { + logError(0, "%s MS CX testes finished!.................OK\n", + tag); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return OK; + } else { + print_frame_i8("MS Init Data (Cx2) =", + array1dTo2d_i8(msCompData.node_data, + msCompData.node_data_size, + msCompData.header.sense_node), + msCompData.header.force_node, + msCompData.header.sense_node); + print_frame_short(" TOT MS Init Data (Cx) =", + array1dTo2d_short(totCompData.node_data, + totCompData.node_data_size, + totCompData.header. + sense_node), + totCompData.header.force_node, + totCompData.header.sense_node); + logError(0, + "%s MS CX testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (thresholds_min != NULL) { + kfree(thresholds_min); + thresholds_min = NULL; + } + if (thresholds_max != NULL) { + kfree(thresholds_max); + thresholds_max = NULL; + } + if (adjhor != NULL) { + kfree(adjhor); + adjhor = NULL; + } + if (adjvert != NULL) { + kfree(adjvert); + adjvert = NULL; + } + if (totCompData.node_data != NULL) { + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } + if (total_adjhor != NULL) { + kfree(total_adjhor); + total_adjhor = NULL; + } + if (total_adjvert != NULL) { + kfree(total_adjvert); + total_adjvert = NULL; + } + if (msCompData.node_data != NULL) { + kfree(msCompData.node_data); + msCompData.node_data = NULL; + } + return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + } + +ERROR_LIMITS: + + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (thresholds_min != NULL) { + kfree(thresholds_min); + thresholds_min = NULL; + } + if (thresholds_max != NULL) { + kfree(thresholds_max); + thresholds_max = NULL; + } + if (adjhor != NULL) { + kfree(adjhor); + adjhor = NULL; + } + if (adjvert != NULL) { + kfree(adjvert); + adjvert = NULL; + } + if (totCompData.node_data != NULL) { + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } + if (total_adjhor != NULL) { + kfree(total_adjhor); + total_adjhor = NULL; + } + if (total_adjvert != NULL) { + kfree(total_adjvert); + total_adjvert = NULL; + } + if (msCompData.node_data != NULL) { + kfree(msCompData.node_data); + msCompData.node_data = NULL; + } + return ret; +} + +/** + * Perform all the tests selected in a TestTodo variable related to MS Init data of the keys + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ms_key_cx(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret; + int count_fail = 0; + int num_keys = 0; + int *thresholds = NULL; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + int trows, tcolumns; + MutualSenseData msCompData; + TotMutualSenseData totCompData; + short container; + ret = readMutualSenseCompensationData(LOAD_CX_MS_KEY, &msCompData); + + if (ret < 0) { + logError(1, + "%s production_test_data: readMutualSenseCompensationData failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + if (msCompData.header.force_node > msCompData.header.sense_node) + num_keys = msCompData.header.force_node; + else + num_keys = msCompData.header.sense_node; + + + if (todo->MutualKeyCx1 == 1) { + logError(1, "%s MS KEY CX1 TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + MS_KEY_CX1_MIN_MAX, &thresholds, + &trows, &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_KEY_CX1_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)msCompData.cx1; + ret = + checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax MS CX1 failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS KEY CX1 TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS KEY CX1 TEST:.................OK \n\n", + tag); + } else + logError(0, "%s MS KEY CX1 TEST:.................SKIPPED \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + + if (todo->MutualKeyCx2 == 1) { + logError(1, "%s MS KEY CX2 TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, MS_KEY_CX2_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, MS_KEY_CX2_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != msCompData.header.force_node + || tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_KEY_CX2_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(msCompData.node_data, msCompData.header.force_node, msCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap MS KEY CX2 failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS KEY CX2 TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS KEY CX2 TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, "%s MS CX2 TEST:.................SKIPPED \n\n", + tag); + + + if (todo->MutualKeyCxTotal == 1) { + logError(1, "%s MS KEY TOTAL CX TEST: \n", tag); + ret = + readTotMutualSenseCompensationData(LOAD_PANEL_CX_TOT_MS_KEY, + &totCompData); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeTotalCx failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, MS_KEY_TOTAL_CX_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, MS_KEY_TOTAL_CX_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_KEY_TOTAL_CX_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.node_data, totCompData.header.force_node, totCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap MS TOTAL KEY CX TEST failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s MS KEY TOTAL CX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS KEY TOTAL CX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } else + logError(0, + "%s MS KEY TOTAL CX TEST:.................SKIPPED \n", + tag); + +ERROR: + logError(0, "%s \n", tag); + + if (count_fail == 0) { + logError(0, + "%s MS KEY CX testes finished!.................OK\n", + tag); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return OK; + } else { + print_frame_i8("MS Key Init Data (Cx2) =", + array1dTo2d_i8(msCompData.node_data, + msCompData.node_data_size, + msCompData.header.sense_node), + msCompData.header.force_node, + msCompData.header.sense_node); + logError(0, + "%s MS Key CX testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (thresholds_min != NULL) { + kfree(thresholds_min); + thresholds_min = NULL; + } + if (thresholds_max != NULL) { + kfree(thresholds_max); + thresholds_max = NULL; + } + if (msCompData.node_data != NULL) { + kfree(msCompData.node_data); + msCompData.node_data = NULL; + } + if (totCompData.node_data != NULL) { + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } + return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + } + +ERROR_LIMITS: + + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (thresholds_min != NULL) { + kfree(thresholds_min); + thresholds_min = NULL; + } + if (thresholds_max != NULL) { + kfree(thresholds_max); + thresholds_max = NULL; + } + if (msCompData.node_data != NULL) { + kfree(msCompData.node_data); + msCompData.node_data = NULL; + } + if (totCompData.node_data != NULL) { + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } + return ret; +} + +/** + * Perform all the tests selected in a TestTodo variable related to MS LowPower + * Init data (touch, keys etc..) + * @param path_limits name of Production Limit file to load or + * "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check + * failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error + */ +int production_test_ms_cx_lp(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int ret; + int count_fail = 0; + + int *thresholds = NULL; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + int trows, tcolumns; + + MutualSenseData msCompData; + TotMutualSenseData totCompData; + + u8 *adjhor = NULL; + + u8 *adjvert = NULL; + + u16 container; + /* u16 *total_cx = NULL; */ + u16 *total_adjhor = NULL; + u16 *total_adjvert = NULL; + + + /* MS CX TEST */ + logError(0, "%s\n", tag); + + ret = readMutualSenseCompensationData(LOAD_CX_MS_LOW_POWER, &msCompData); + /* read MS compensation data */ + if (ret < 0) { + logError(1, + "%s production_test_data: readMutualSenseCompensationData failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + ret = readTotMutualSenseCompensationData(LOAD_PANEL_CX_TOT_MS_LOW_POWER, + &totCompData); + /* read TOT MS compensation data */ + if (ret < 0) { + logError(1, + "%s production_test_data: readTotMutualSenseCompensationData failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return ret | ERROR_PROD_TEST_DATA; + } + + if (todo->MutualCx1LP == 1) { + logError(1, "%s MS LP CX1 TEST:\n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX1_LP_MIN_MAX, &thresholds, + &trows, &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX1_LP_MIN_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (u16)msCompData.cx1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + /* check the limits */ + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax MS LP CX1 failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, "%s MS LP CX1 TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, "%s MS LP CX1 TEST:.................OK\n\n", + tag); + } else + logError(0, "%s MS LP CX1 TEST:.................SKIPPED\n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + + if (todo->MutualCx2LP == 1) { + logError(1, "%s MS LP CX2 MIN MAX TEST:\n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_LP_MAP_MIN, &thresholds_min, + &trows, &tcolumns); + /* load min thresholds */ + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_LP_MAP_MIN failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_LP_MAP_MAX, &thresholds_max, + &trows, &tcolumns); + /* load max thresholds */ + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_LP_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + thresholds_min, thresholds_max); + /* check the limits */ + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap MS LP CX2 MIN MAX failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s MS LP CX2 MIN MAX TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS LP CX2 MIN MAX TEST:.................OK\n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s MS LP CX2 MIN MAX TEST:.................SKIPPED\n\n", + tag); + + if (todo->MutualCx2AdjLP == 1) { + logError(1, "%s MS LP CX2 ADJ TEST:\n", tag); + /* MS CX2 ADJ HORIZ */ + logError(0, "%s MS LP CX2 ADJ HORIZ TEST:\n", tag); + + ret = computeAdjHoriz(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + &adjhor); + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + logError(0, "%s MS LP CX2 ADJ HORIZ computed!\n", tag); + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_ADJH_LP_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node || + tcolumns != msCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_ADJH_LP_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjhor, msCompData.header.force_node, + msCompData.header.sense_node - 1, + thresholds_max); + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj CX2 ADJH LP failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s MS LP CX2 ADJ HORIZ TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS LP CX2 ADJ HORIZ TEST:.................OK\n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjhor); + adjhor = NULL; + + /* MS CX2 ADJ VERT */ + logError(0, "%s MS LP CX2 ADJ VERT TEST:\n", tag); + + ret = computeAdjVert(msCompData.node_data, + msCompData.header.force_node, + msCompData.header.sense_node, + &adjvert); + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + logError(0, "%s MS LP CX2 ADJ VERT computed!\n", tag); + + ret = parseProductionTestLimits(path_limits, &limit_file, + MS_CX2_ADJV_LP_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + if (ret < 0 || (trows != msCompData.header.force_node - 1 || + tcolumns != msCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_CX2_ADJV_LP_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjvert, msCompData.header.force_node - + 1, msCompData.header.sense_node - 1, + thresholds_max); + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj CX2 ADJV LP failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s MS LP CX2 ADJ HORIZ TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS LP CX2 ADJ VERT TEST:.................OK\n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjvert); + adjvert = NULL; + } else + logError(0, "%s MS LP CX2 ADJ TEST:.................SKIPPED\n\n", + tag); + + /* START OF TOTAL CHECK */ + + if (todo->MutualCxTotalLP == 1 || todo->MutualCxTotalAdjLP == 1) { + if (todo->MutualCxTotalLP == 1) { + logError(1, "%s MS TOTAL LP CX MIN MAX TEST:\n", tag); + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_LP_MAP_MIN, + &thresholds_min, + &trows, &tcolumns); + /* load min thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != + totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_LP_MAP_MIN failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_LP_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + /* load max thresholds */ + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != + totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_LP_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + thresholds_min, + thresholds_max); + /* check the limits */ + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap MS TOTAL CX LP TEST failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s MS TOTAL CX LP MIN MAX TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS TOTAL CX LP MIN MAX TEST:.................OK\n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s MS TOTAL CX LP MIN MAX TEST:.................SKIPPED\n\n", + tag); + + + if (todo->MutualCxTotalAdjLP == 1) { + /* MS TOTAL CX ADJ HORIZ */ + logError(1, "%s MS TOTAL CX ADJ HORIZ LP TEST:\n", tag); + + ret = computeAdjHorizTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + &total_adjhor); + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + logError(0, "%s MS TOTAL CX ADJ HORIZ LP computed!\n", + tag); + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_ADJH_LP_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + if (ret < 0 || (trows != + totCompData.header.force_node || + tcolumns != + totCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJH_LP_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjhor, + totCompData.header. + force_node, + totCompData.header. + sense_node - 1, + thresholds_max); + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJH LP failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s MS TOTAL CX ADJ HORIZ LP TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS TOTAL CX ADJ HORIZ LP TEST:.................OK\n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjhor); + total_adjhor = NULL; + + /* MS TOTAL CX ADJ VERT */ + logError(0, "%s MS TOTAL CX ADJ VERT LP TEST:\n", tag); + + ret = computeAdjVertTotal(totCompData.node_data, + totCompData.header.force_node, + totCompData.header.sense_node, + &total_adjvert); + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + logError(0, "%s MS TOTAL CX ADJ VERT LP computed!\n", tag); + + ret = parseProductionTestLimits(path_limits, + &limit_file, + MS_TOTAL_CX_ADJV_LP_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + if (ret < 0 || (trows != totCompData.header.force_node - + 1 || tcolumns != + totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits MS_TOTAL_CX_ADJV_LP_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjvert, + totCompData.header. + force_node - 1, + totCompData.header. + sense_node - 1, + thresholds_max); + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj MS TOTAL CX ADJV failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s MS TOTAL CX ADJ HORIZ LP TEST:.................FAIL\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s MS TOTAL CX ADJ VERT LP TEST:.................OK\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjvert); + total_adjvert = NULL; + } else + logError(0, + "%s MS TOTAL CX ADJ LP TEST:.................SKIPPED\n", + tag); + + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } else + logError(0, "%s MS TOTAL CX LP TEST:.................SKIPPED\n", + tag); + + + +ERROR: + logError(0, "%s\n", tag); + if (count_fail == 0) { + logError(0, "%s MS LP CX testes finished!.................OK\n", + tag); + kfree(msCompData.node_data); + msCompData.node_data = NULL; + return OK; + } else { + print_frame_i8("MS LP Init Data (Cx2) =", array1dTo2d_i8( + msCompData.node_data, + msCompData.node_data_size, + msCompData.header.sense_node), + msCompData.header.force_node, + msCompData.header.sense_node); + print_frame_short(" TOT MS LP Init Data (Cx) =", array1dTo2d_short( + totCompData.node_data, + totCompData.node_data_size, + totCompData.header.sense_node), + totCompData.header.force_node, + totCompData.header.sense_node); + logError(0, + "%s MS LP CX testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (thresholds_min != NULL) { + kfree(thresholds_min); + thresholds_min = NULL; + } + if (thresholds_max != NULL) { + kfree(thresholds_max); + thresholds_max = NULL; + } + if (adjhor != NULL) { + kfree(adjhor); + adjhor = NULL; + } + if (adjvert != NULL) { + kfree(adjvert); + adjvert = NULL; + } + if (totCompData.node_data != NULL) { + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } + if (total_adjhor != NULL) { + kfree(total_adjhor); + total_adjhor = NULL; + } + if (total_adjvert != NULL) { + kfree(total_adjvert); + total_adjvert = NULL; + } + if (msCompData.node_data != NULL) { + kfree(msCompData.node_data); + msCompData.node_data = NULL; + } + return ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA; + } + +ERROR_LIMITS: + if (thresholds != NULL) { + kfree(thresholds); + thresholds = NULL; + } + if (thresholds_min != NULL) { + kfree(thresholds_min); + thresholds_min = NULL; + } + if (thresholds_max != NULL) { + kfree(thresholds_max); + thresholds_max = NULL; + } + if (adjhor != NULL) { + kfree(adjhor); + adjhor = NULL; + } + if (adjvert != NULL) { + kfree(adjvert); + adjvert = NULL; + } + if (totCompData.node_data != NULL) { + kfree(totCompData.node_data); + totCompData.node_data = NULL; + } + if (total_adjhor != NULL) { + kfree(total_adjhor); + total_adjhor = NULL; + } + if (total_adjvert != NULL) { + kfree(total_adjvert); + total_adjvert = NULL; + } + if (msCompData.node_data != NULL) { + kfree(msCompData.node_data); + msCompData.node_data = NULL; + } + return ret; +} + +int production_test_ss_hover_raw(char *path_limits, int stop_on_fail, + TestToDo *todo){ + int ret; + int rows, columns; + int *thresholds = NULL; + int trows, tcolumns; + u8 hover_cnt[4] = {0xa8, 0x0b, 0x01, 0x00}; + + SelfSenseFrame ssHoverRawFrame; + int count_fail = 0; + + ret = fts_write_dma_safe(hover_cnt, sizeof(hover_cnt)); + if (ret != OK) { + logError(1, + "%s hover clear count ERROR = %d\n", tag, ret); + goto ERROR_LIMITS; + } + + logError(0, "%s Getting SS Hover Frame...\n", tag); + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_HOVER); + msleep(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + msleep(WAIT_AFTER_SENSEOFF); + ret |= getSSFrame3(SS_HVR_RAW, &ssHoverRawFrame); + /* SS Hover RAW FORCE TEST */ + logError(0, "%s SS Hover RAW FORCE TEST:\n", tag); + + logError(0, "%s SS RAW FORCE MIN MAX TEST:\n", tag); + if (todo->SelfHoverForceRaw == 1) { + columns = 1; + rows = ssHoverRawFrame.header.force_node; + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_HOVER_RAW_FORCE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_HOVER_RAW_FORCE_MIN_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMinMax(ssHoverRawFrame.force_data, rows,columns, thresholds[0], thresholds[1]); + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS HOVER RAW FORCE failed... ERROR COUNT = %d\n",tag, ret); + logError(0, + "%s SS Hover RAW FORCE MIN MAX TEST:.................FAIL\n\n", tag); + count_fail += 1; + print_frame_short("SS Raw force frame =", + array1dTo2d_short( + ssHoverRawFrame.force_data, + rows * + columns, + columns), rows, + columns); + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW FORCE MIN MAX TEST:.................OK\n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW FORCE MIN MAX TEST:.................SKIPPED\n\n", + tag); + logError(0, "%s\n", tag); + /* SS Hover RAW SENSE TEST */ + logError(0, "%s SS Hover RAW SENSE TEST:\n", tag); + + logError(0, "%s SS RAW SENSE MIN MAX TEST:\n", tag); + if (todo->SelfHoverSenceRaw == 1) { + columns = ssHoverRawFrame.header.sense_node; + rows = 1; + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_HOVER_RAW_SENSE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMinMax(ssHoverRawFrame.sense_data, rows, columns, thresholds[0], thresholds[1]); + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS Hover RAW SENSE failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s SS Hover RAW SENSE MIN MAX TEST:.................FAIL\n", + tag); + count_fail += 1; + print_frame_short("SS Hover Raw sense frame =", + array1dTo2d_short( + ssHoverRawFrame.sense_data, + rows * + columns, + columns), rows, + columns); + if (stop_on_fail) { + ret = ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS Hover RAW SENSE MIN MAX TEST:.................OK\n",tag); + + kfree(thresholds); + thresholds = NULL; + } + +ERROR_LIMITS: + if (ssHoverRawFrame.force_data != NULL) + kfree(ssHoverRawFrame.force_data); + if (ssHoverRawFrame.sense_data != NULL) + kfree(ssHoverRawFrame.sense_data); + if (thresholds != NULL) + kfree(thresholds); + + return ret; +} + +/** + * Perform all the test selected in a TestTodo variable related to SS raw data (touch, keys etc..) + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int ret; + int count_fail = 0; + int rows, columns; + SelfSenseFrame ssRawFrame; + int *thresholds = NULL; + int trows, tcolumns; + logError(0, "%s \n", tag); + /******************************* Self Sense Test *******************************/ + logError(0, "%s Getting SS Frame... \n", tag); + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_ACTIVE); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getSSFrame3(SS_RAW, &ssRawFrame); + + if (ret < 0) { + logError(1, + "%s production_test_data: getSSFrame failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + + if (todo->SelfForceRaw == 1 || todo->SelfForceRawGap == 1) { + columns = 1; + rows = ssRawFrame.header.force_node; + logError(0, "%s SS RAW FORCE MIN MAX TEST: \n", tag); + + if (todo->SelfForceRaw == 1) { + logError(1, "%s SS RAW FORCE MIN MAX TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_FORCE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMinMax(ssRawFrame.force_data, rows, + columns, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS RAW FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + print_frame_short("SS Raw force frame =", + array1dTo2d_short + (ssRawFrame.force_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW (PROXIMITY) FORCE MIN MAX TEST:.................SKIPPED \n\n", + tag); + + logError(0, "%s \n", tag); + + if (todo->SelfForceRawGap == 1) { + logError(1, "%s SS RAW FORCE GAP TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_FORCE_GAP, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_GAP failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsGap(ssRawFrame.force_data, rows, columns, + thresholds[0]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsGap SS RAW FORCE GAP failed... ERROR = %08X \n", + tag, ret); + logError(0, + "%s SS RAW FORCE GAP TEST:.................FAIL \n\n", + tag); + count_fail += 1; + print_frame_short("SS Raw force frame =", + array1dTo2d_short + (ssRawFrame.force_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW (PROXIMITY) FORCE GAP TEST:.................SKIPPED \n\n", + tag); + + kfree(ssRawFrame.force_data); + ssRawFrame.force_data = NULL; + } else + logError(0, + "%s SS RAW (PROXIMITY) FORCE TEST:.................SKIPPED \n\n", + tag); + + logError(0, "%s \n", tag); + + if (todo->SelfSenseRaw == 1 || todo->SelfSenseRawGap == 1) { + columns = ssRawFrame.header.sense_node; + rows = 1; + + if (todo->SelfSenseRaw == 1) { + logError(1, "%s SS RAW SENSE MIN MAX TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_SENSE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMinMax(ssRawFrame.sense_data, rows, + columns, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS RAW SENSE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS RAW SENSE MIN MAX TEST:.................FAIL \n", + tag); + count_fail += 1; + print_frame_short("SS Raw sense frame =", + array1dTo2d_short + (ssRawFrame.sense_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW (PROXIMITY) SENSE MIN MAX TEST:.................SKIPPED \n", + tag); + + logError(0, "%s \n", tag); + + if (todo->SelfSenseRawGap == 1) { + logError(1, "%s SS RAW SENSE GAP TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_SENSE_GAP, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_GAP failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsGap(ssRawFrame.sense_data, rows, columns, + thresholds[0]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsGap SS RAW SENSE GAP failed... ERROR = %08X \n", + tag, ret); + logError(0, + "%s SS RAW SENSE GAP TEST:.................FAIL \n", + tag); + count_fail += 1; + print_frame_short("SS Raw sense frame =", + array1dTo2d_short + (ssRawFrame.sense_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW (PROXIMITY) SENSE GAP TEST:.................SKIPPED \n", + tag); + + kfree(ssRawFrame.sense_data); + ssRawFrame.sense_data = NULL; + } + + ret = production_test_ss_raw_lp(path_limits, stop_on_fail, todo); + + if (ret < OK) { + logError(1, + "%s production_test_data: production_test_ss_raw_lp failed... ERROR = %08X \n", + tag, ret); + count_fail += 1; + } + if (todo->SelfHoverForceRaw == 1 || todo->SelfHoverSenceRaw) { + ret = production_test_ss_hover_raw(path_limits, stop_on_fail, todo); + if (ret < OK) { + logError(1, + "%s production_test_data: production_test_ss_hover_raw failed... ERROR = %08X\n", + tag, ret); + count_fail += 1; + } + } + + logError(0, "%s \n", tag); + + if (count_fail == 0) { + logError(0, "%s SS RAW testes finished!.................OK\n\n", + tag); + return OK; + } else { + logError(0, + "%s SS RAW testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + } + +ERROR_LIMITS: + + if (ssRawFrame.force_data != NULL) + kfree(ssRawFrame.force_data); + + if (ssRawFrame.sense_data != NULL) + kfree(ssRawFrame.sense_data); + + if (thresholds != NULL) + kfree(thresholds); + + return ret; +} + +/** + * Perform all the test selected in a TestTodo variable related to SS raw data low power + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ss_raw_lp(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret; + int count_fail = 0; + int rows, columns; + SelfSenseFrame ssRawFrame; + int *thresholds = NULL; + int trows, tcolumns; + logError(0, "%s \n", tag); + /******************************* Self Sense Test *******************************/ + ret = setScanMode(SCAN_MODE_LOCKED, LOCKED_LP_DETECT); + mdelay(WAIT_FOR_FRESH_FRAMES); + ret |= setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + ret |= getSSFrame3(SS_RAW, &ssRawFrame); + + if (ret < 0) { + logError(1, + "%s production_test_data: getSSFrame failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + + if (todo->SelfForceRawLP == 1 || todo->SelfForceRawGapLP == 1) { + columns = 1; + rows = ssRawFrame.header.force_node; + + if (todo->SelfForceRawLP == 1) { + logError(1, "%s SS RAW LP FORCE MIN MAX TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_LP_FORCE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMinMax(ssRawFrame.force_data, rows, + columns, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS RAW FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS RAW LP FORCE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + print_frame_short("SS Raw LP force frame =", + array1dTo2d_short + (ssRawFrame.force_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW LP FORCE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW LP FORCE MIN MAX TEST:.................SKIPPED \n\n", + tag); + + logError(0, "%s \n", tag); + + if (todo->SelfForceRawGapLP == 1) { + logError(1, "%s SS RAW LP FORCE GAP TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_LP_FORCE_GAP, + &thresholds, &trows, + &tcolumns); + + if (ret < OK || (trows != 1 || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_FORCE_GAP failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsGap(ssRawFrame.force_data, rows, columns, + thresholds[0]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsGap SS RAW FORCE GAP failed... ERROR = %08X \n", + tag, ret); + logError(0, + "%s SS RAW LP FORCE GAP TEST:.................FAIL \n\n", + tag); + count_fail += 1; + print_frame_short("SS Raw LP force frame =", + array1dTo2d_short + (ssRawFrame.force_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW LP FORCE GAP TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW LP FORCE GAP TEST:.................SKIPPED \n\n", + tag); + + kfree(ssRawFrame.force_data); + ssRawFrame.force_data = NULL; + } else + logError(0, + "%s SS RAW LP FORCE TEST:.................SKIPPED \n\n", + tag); + + logError(0, "%s \n", tag); + + if (todo->SelfSenseRawLP == 1 || todo->SelfSenseRawGapLP == 1) { + columns = ssRawFrame.header.sense_node; + rows = 1; + logError(0, "%s SS RAW LP SENSE MIN MAX TEST: \n", tag); + + if (todo->SelfSenseRawLP == 1) { + logError(1, "%s SS RAW LP SENSE MIN MAX TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_LP_SENSE_MIN_MAX, + &thresholds, &trows, + &tcolumns); + + if (ret < OK || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMinMax(ssRawFrame.sense_data, rows, + columns, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS RAW SENSE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS RAW LP SENSE MIN MAX TEST:.................FAIL \n", + tag); + count_fail += 1; + print_frame_short("SS Raw LP sense frame =", + array1dTo2d_short + (ssRawFrame.sense_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW SENSE MIN MAX TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW LP SENSE MIN MAX TEST:.................SKIPPED \n", + tag); + + logError(0, "%s \n", tag); + + if (todo->SelfSenseRawGapLP == 1) { + logError(1, "%s SS RAW LP SENSE GAP TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_RAW_LP_SENSE_GAP, + &thresholds, &trows, + &tcolumns); + + if (ret < OK || (trows != 1 || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_RAW_SENSE_GAP failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsGap(ssRawFrame.sense_data, rows, columns, + thresholds[0]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsGap SS RAW SENSE GAP failed... ERROR = %08X \n", + tag, ret); + logError(0, + "%s SS RAW LP SENSE GAP TEST:.................FAIL \n", + tag); + count_fail += 1; + print_frame_short("SS Raw LP sense frame =", + array1dTo2d_short + (ssRawFrame.sense_data, + rows * columns, columns), + rows, columns); + + if (stop_on_fail) { + ret = + ERROR_PROD_TEST_DATA | + ERROR_TEST_CHECK_FAIL; + goto ERROR_LIMITS; + } + } else + logError(0, + "%s SS RAW LP SENSE GAP TEST:.................OK \n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS RAW LP SENSE GAP TEST:.................SKIPPED \n", + tag); + + kfree(ssRawFrame.sense_data); + ssRawFrame.sense_data = NULL; + } + + logError(0, "%s \n", tag); + + if (count_fail == 0) { + logError(0, + "%s SS RAW LP testes finished!.................OK\n\n", + tag); + return OK; + } else { + logError(0, + "%s SS RAW LP testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + } + +ERROR_LIMITS: + + if (ssRawFrame.force_data != NULL) + kfree(ssRawFrame.force_data); + + if (ssRawFrame.sense_data != NULL) + kfree(ssRawFrame.sense_data); + + if (thresholds != NULL) + kfree(thresholds); + + return ret; +} + +int production_test_ss_hover_ix(char *path_limits, int stop_on_fail, TestToDo *todo){ + TotSelfSenseData ssHoverCompData; + int ret; + int trows, tcolumns; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + int count_fail = 0; + + /* ret = readSelfSenseCompensationData(LOAD_CX_SS_HOVER, &ssHoverCompData); */ + ret = readTotSelfSenseCompensationData(STAPI_HOST_DATA_ID_PANEL_CX_SS_HVR, &ssHoverCompData); + /* read the SS compensation data */ + if (ret < 0) { + logError(1, + "%s production_test_data: readSelfSenseCompensationData failed... ERROR %08X\n",tag, ERROR_PROD_TEST_DATA); + return ret | ERROR_PROD_TEST_DATA; + } + + logError(0, "%s SS Hover TOTAL IX FORCE TEST:\n", tag); + logError(0, "%s SS Hover TOTAL IX FORCE MIN MAX TEST:\n", tag); + if (todo->SelfHoverForceIxTotal == 1) { + ret = parseProductionTestLimits(path_limits, &limit_file, SS_HOVER_TOTAL_IX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != ssHoverCompData.header.force_node || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MIN failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file,SS_TOTAL_IX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != + ssHoverCompData.header.force_node || + tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotalFromU(ssHoverCompData.ix_fm,ssHoverCompData.header. + force_node, 1, + thresholds_min, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s SS TOTAL IX FORCE MIN MAX TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL IX FORCE MIN MAX TEST:.................OK\n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS Hover TOTAL IX FORCE MIN MAX TEST:.................SKIPPED\n", + tag); + + logError(0, "%s SS HOVER TOTAL IX SENSE MIN MAX TEST:\n", tag); + if (todo->SelfHoverSenceIxTotal == 1) { + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_SENSE_MAP_MIN, + &thresholds_min, + &trows, &tcolumns); + /* load the min thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssHoverCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MIN failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, + &limit_file, + SS_TOTAL_IX_SENSE_MAP_MAX, + &thresholds_max, + &trows, &tcolumns); + /* load the max thresholds */ + if (ret < 0 || (trows != 1 || tcolumns != + ssHoverCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MAX failed... ERROR %08X\n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotalFromU(ssHoverCompData.ix_sn, 1, + ssHoverCompData.header. + sense_node, + thresholds_min, + thresholds_max); + /* check the values with thresholds */ + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL IX SENSE failed... ERROR COUNT = %d\n", + tag, ret); + logError(0, + "%s SS Hover TOTAL IX SENSE MIN MAX TEST:.................FAIL\n\n", + tag); + count_fail += 1; + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL IX SENSE MIN MAX TEST:.................OK\n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS Hover TOTAL IX SENSE MIN MAX TEST:.................SKIPPED\n", + tag); +ERROR: + logError(0, "%s\n", tag); + if (count_fail == 0) { + kfree(ssHoverCompData.ix_fm); + ssHoverCompData.ix_fm = NULL; + kfree(ssHoverCompData.ix_sn); + ssHoverCompData.ix_sn = NULL; + kfree(ssHoverCompData.cx_fm); + ssHoverCompData.cx_fm = NULL; + kfree(ssHoverCompData.cx_sn); + ssHoverCompData.cx_sn = NULL; + logError(0, + "%s SS Hover IX testes finished!.................OK\n\n", + tag); + return OK; + } else { + print_frame_u16("TOT SS hover Init Data Ix_fm = ", array1dTo2d_u16( + ssHoverCompData.ix_fm, + ssHoverCompData.header.force_node, 1), + ssHoverCompData.header.force_node, 1); + print_frame_short("TOT SS hover hover Init Data Cx_fm = ", + array1dTo2d_short(ssHoverCompData.cx_fm, + ssHoverCompData.header. + force_node, 1), + ssHoverCompData.header.force_node, 1); + print_frame_u16("TOT SS hover Init Data Ix_sn = ", array1dTo2d_u16( + ssHoverCompData.ix_sn, + ssHoverCompData.header.sense_node, + ssHoverCompData.header.sense_node), 1, + ssHoverCompData.header.sense_node); + print_frame_short("TOT SS hover Init Data Cx_sn = ", + array1dTo2d_short(ssHoverCompData.cx_sn, + ssHoverCompData.header. + sense_node, + ssHoverCompData.header. + sense_node), + 1, ssHoverCompData.header.sense_node); + logError(0, + "%s SS hover IX CX testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (ssHoverCompData.ix_fm != NULL) + kfree(ssHoverCompData.ix_fm); + if (ssHoverCompData.ix_sn != NULL) + kfree(ssHoverCompData.ix_sn); + if (ssHoverCompData.cx_fm != NULL) + kfree(ssHoverCompData.cx_fm); + if (ssHoverCompData.cx_sn != NULL) + kfree(ssHoverCompData.cx_sn); + return ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA; + } +ERROR_LIMITS: + if (thresholds_min != NULL) + kfree(thresholds_min); + if (thresholds_max != NULL) + kfree(thresholds_max); + if (ssHoverCompData.ix_fm != NULL) + kfree(ssHoverCompData.ix_fm); + if (ssHoverCompData.ix_sn != NULL) + kfree(ssHoverCompData.ix_sn); + if (ssHoverCompData.cx_fm != NULL) + kfree(ssHoverCompData.cx_fm); + if (ssHoverCompData.cx_sn != NULL) + kfree(ssHoverCompData.cx_sn); + return ret; +} + +/** + * Perform all the tests selected in a TestTodo variable related to SS Init data (touch, keys etc..) + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, + TestToDo *todo) +{ + int ret; + int count_fail = 0; + int *thresholds = NULL; + int trows, tcolumns; + int *thresholds_min = NULL; + int *thresholds_max = NULL; + SelfSenseData ssCompData; + TotSelfSenseData totCompData; + u8 *adjhor = NULL; + u8 *adjvert = NULL; + short container; + u16 *total_adjhor = NULL; + u16 *total_adjvert = NULL; + logError(0, "%s \n", tag); + ret = readSelfSenseCompensationData(LOAD_CX_SS_TOUCH, &ssCompData); + + if (ret < 0) { + logError(1, + "%s production_test_data: readSelfSenseCompensationData failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + return (ret | ERROR_PROD_TEST_DATA); + } + + ret = + readTotSelfSenseCompensationData(LOAD_PANEL_CX_TOT_SS_TOUCH, + &totCompData); + + if (ret < 0) { + logError(1, + "%s production_test_data: readTotSelfSenseCompensationData failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + kfree(ssCompData.ix2_fm); + kfree(ssCompData.ix2_sn); + kfree(ssCompData.cx2_fm); + kfree(ssCompData.cx2_sn); + return (ret | ERROR_PROD_TEST_DATA); + } + + /********************************************************* SS FORCE IX ****************************************************************/ + + if (todo->SelfForceIx1 == 1) { + logError(1, "%s SS IX1 FORCE TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_IX1_FORCE_MIN_MAX, &thresholds, + &trows, &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX1_FORCE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)ssCompData.f_ix1; + ret = + checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS IX1 FORCE TEST failed... ERROR COUNT = %d \n", + tag, ret); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS IX1 FORCE TEST:.................OK \n\n", + tag); + } else + logError(0, + "%s SS IX1 FORCE TEST:.................SKIPPED \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + + if (todo->SelfForceIx2 == 1) { + logError(1, "%s SS IX2 FORCE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_IX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_IX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapFromU(ssCompData.ix2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS IX2 FORCE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS IX2 FORCE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS IX2 FORCE MIN MAX TEST:.................SKIPPED \n\n", + tag); + + + if (todo->SelfForceIx2Adj == 1) { + logError(1, "%s SS IX2 FORCE ADJ TEST: \n", tag); + ret = + computeAdjVertFromU(ssCompData.ix2_fm, + ssCompData.header.force_node, 1, + &adjvert); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert SS IX2 FORCE ADJV failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s SS IX2 FORCE ADJV computed! \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_IX2_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != ssCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX2_FORCE_ADJV_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS IX2 FORCE ADJV TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS IX2 FORCE ADJV TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjvert); + adjvert = NULL; + } else + logError(0, + "%s SS IX2 FORCE ADJ TEST:.................SKIPPED \n\n", + tag); + + + if (todo->SelfForceIxTotal == 1 || todo->SelfForceIxTotalAdj == 1) { + + if (todo->SelfForceIxTotal == 1) { + logError(1, "%s SS TOTAL IX FORCE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_IX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_IX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotalFromU(totCompData.ix_fm, totCompData.header.force_node, 1, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL IX FORCE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL IX FORCE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS TOTAL IX FORCE MIN MAX TEST:.................SKIPPED \n", + tag); + + + if (todo->SelfForceIxTotalAdj == 1) { + logError(1, "%s SS TOTAL IX FORCE ADJVERT TEST: \n", + tag); + ret = + computeAdjVertTotalFromU(totCompData.ix_fm, + totCompData.header. + force_node, 1, + &total_adjvert); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert SS TOTAL IX FORCE ADJV failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s SS TOTAL IX FORCE ADJV computed! \n", + tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_IX_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_FORCE_ADJV_MAP_MAX... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjvert, totCompData.header.force_node - 1, 1, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL IX FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL IX FORCE ADJV TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL IX FORCE ADJV TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjvert); + total_adjvert = NULL; + } else + logError(0, + "%s SS TOTAL IX FORCE ADJ TEST:.................SKIPPED \n", + tag); + } else + logError(0, + "%s SS TOTAL IX FORCE TEST:.................SKIPPED \n\n", + tag); + + /********************************************************* SS SENSE IX ****************************************************************/ + + if (todo->SelfSenseIx1 == 1) { + logError(1, "%s SS IX1 SENSE TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_IX1_SENSE_MIN_MAX, &thresholds, + &trows, &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX1_SENSE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)ssCompData.s_ix1; + ret = checkLimitsMinMax(&container, 1, 1, thresholds[0], thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS IX1 SENSE TEST failed... ERROR COUNT = %d \n", + tag, ret); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS IX1 SENSE TEST:.................OK \n\n", + tag); + } else + logError(0, + "%s SS IX1 SENSE TEST:.................SKIPPED \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + + if (todo->SelfSenseIx2 == 1) { + logError(1, "%s SS IX2 SENSE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_IX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_IX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapFromU(ssCompData.ix2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS IX2 SENSE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS IX2 SENSE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS IX2 SENSE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS IX2 SENSE MIN MAX TEST:.................SKIPPED \n\n", + tag); + + + if (todo->SelfSenseIx2Adj == 1) { + logError(1, "%s SS IX2 SENSE ADJHORIZ TEST: \n", tag); + ret = + computeAdjHorizFromU(ssCompData.ix2_sn, 1, + ssCompData.header.sense_node, &adjhor); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz SS IX2 SENSE ADJH failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s SS IX2 SENSE ADJ HORIZ computed! \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_IX2_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != ssCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_ADJH_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj SS IX2 SENSE ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS IX2 SENSE ADJH TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS IX2 SENSE ADJH TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjhor); + adjhor = NULL; + } else + logError(0, + "%s SS IX2 SENSE ADJ TEST:.................SKIPPED \n", + tag); + + + if (todo->SelfSenseIxTotal == 1 || todo->SelfSenseIxTotalAdj == 1) { + + if (todo->SelfSenseIxTotal == 1) { + logError(1, "%s SS TOTAL IX SENSE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_IX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_IX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotalFromU(totCompData.ix_sn, 1, totCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL IX SENSE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL IX SENSE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL IX SENSE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS TOTAL IX SENSE MIN MAX TEST:.................SKIPPED \n", + tag); + + + if (todo->SelfSenseIxTotalAdj == 1) { + logError(1, "%s SS TOTAL IX SENSE ADJHORIZ TEST: \n", + tag); + ret = + computeAdjHorizTotalFromU(totCompData.ix_sn, 1, + totCompData.header. + sense_node, + &total_adjhor); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz SS TOTAL IX SENSE ADJH failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, + "%s SS TOTAL IX SENSE ADJ HORIZ computed! \n", + tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_IX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != + totCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_IX_SENSE_ADJH_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjhor, 1, totCompData.header.sense_node - 1, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj SS TOTAL IX SENSE ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL IX SENSE ADJH TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL IX SENSE ADJH TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjhor); + total_adjhor = NULL; + } else + logError(0, + "%s SS TOTAL IX SENSE ADJ TEST:.................SKIPPED \n", + tag); + } else + logError(0, + "%s SS TOTAL IX SENSE TEST:.................SKIPPED \n", + tag); + + /********************************************************* SS SENSE CX ****************************************************************/ + + if (todo->SelfForceCx1 == 1) { + logError(1, "%s SS CX1 FORCE TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_CX1_FORCE_MIN_MAX, &thresholds, + &trows, &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_CX1_FORCE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)ssCompData.f_cx1; + ret = + checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS CX1 FORCE TEST failed... ERROR COUNT = %d \n", + tag, ret); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS CX1 FORCE TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS CX1 FORCE TEST:.................SKIPPED \n\n", + tag); + + + if (todo->SelfForceCx2 == 1) { + logError(1, "%s SS CX2 FORCE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_CX2_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_CX2_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != ssCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(ssCompData.cx2_fm, ssCompData.header.force_node, 1, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS CX2 FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS CX2 FORCE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS CX2 FORCE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS CX2 FORCE MIN MAX TEST:.................SKIPPED \n", + tag); + + + if (todo->SelfForceCx2Adj == 1) { + logError(1, "%s SS CX2 FORCE ADJVERT TEST: \n", tag); + ret = computeAdjVert(ssCompData.cx2_fm, ssCompData.header.force_node, 1, &adjvert); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert SS CX2 FORCE ADJV failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s SS CX2 FORCE ADJV computed! \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_CX2_FORCE_ADJV_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != ssCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_CX2_FORCE_ADJV_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjvert, ssCompData.header.force_node - 1, 1, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS IX2 FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS CX2 FORCE ADJV TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS CX2 FORCE ADJV TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjvert); + adjvert = NULL; + } else + logError(0, + "%s SS CX2 FORCE ADJ TEST:.................SKIPPED \n\n", + tag); + + + if (todo->SelfForceCxTotal == 1 || todo->SelfForceCxTotalAdj == 1) { + + if (todo->SelfForceCxTotal == 1) { + logError(1, "%s SS TOTAL CX FORCE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_CX_FORCE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_CX_FORCE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.cx_fm, totCompData.header.force_node, 1, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL FORCE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL FORCE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS TOTAL CX FORCE MIN MAX TEST:.................SKIPPED \n", + tag); + + + if (todo->SelfForceCxTotalAdj == 1) { + logError(1, "%s SS TOTAL CX FORCE ADJVERT TEST: \n", + tag); + ret = computeAdjVertTotal(totCompData.cx_fm, totCompData.header.force_node, 1, &total_adjvert); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjVert SS TOTAL CX FORCE ADJV failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s SS TOTAL CX FORCE ADJV computed! \n", + tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_TOTAL_CX_FORCE_ADJV_MAP_MAX, + &thresholds_max, &trows, + &tcolumns); + + if (ret < 0 + || (trows != totCompData.header.force_node - 1 + || tcolumns != 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_FORCE_ADJV_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = + checkLimitsMapAdjTotal(total_adjvert, + totCompData. + header.force_node - 1, 1, + thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL CX FORCE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL CX FORCE ADJV TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL CX FORCE ADJV TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjvert); + total_adjvert = NULL; + } else + logError(0, + "%s SS TOTAL CX FORCE ADJ TEST:.................SKIPPED \n", + tag); + } else + logError(0, + "%s SS TOTAL CX FORCE TEST:.................SKIPPED \n\n", + tag); + + /********************************************************* SS SENSE CX ****************************************************************/ + + if (todo->SelfSenseCx1 == 1) { + logError(1, "%s SS CX1 SENSE TEST: \n", tag); + ret = + parseProductionTestLimits(path_limits, &limit_file, + SS_CX1_SENSE_MIN_MAX, &thresholds, + &trows, &tcolumns); + + if (ret < 0 || (trows != 1 || tcolumns != 2)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_CX1_SENSE_MIN_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + container = (short)ssCompData.s_cx1; + ret = + checkLimitsMinMax(&container, 1, 1, thresholds[0], + thresholds[1]); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMinMax SS CX1 SENSE TEST failed... ERROR COUNT = %d \n", + tag, ret); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS CX1 SENSE TEST:.................OK \n\n", + tag); + + kfree(thresholds); + thresholds = NULL; + } else + logError(0, + "%s SS CX1 SENSE TEST:.................SKIPPED \n\n", + tag); + + + if (todo->SelfSenseCx2 == 1) { + logError(1, "%s SS CX2 SENSE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_CX2_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_CX2_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != ssCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_CX2_SENSE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMap(ssCompData.cx2_sn, 1, ssCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS CX2 SENSE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS CX2 SENSE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS CX2 SENSE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS CX2 SENSE MIN MAX TEST:.................SKIPPED \n", + tag); + + + if (todo->SelfSenseCx2Adj == 1) { + logError(1, "%s SS CX2 SENSE ADJHORIZ TEST: \n", tag); + ret = + computeAdjHoriz(ssCompData.cx2_sn, 1, + ssCompData.header.sense_node, &adjhor); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz SS CX2 SENSE ADJH failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, "%s SS CX2 SENSE ADJH computed! \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_CX2_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != ssCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_IX2_SENSE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdj(adjhor, 1, ssCompData.header.sense_node - 1, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj SS CX2 SENSE ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS CX2 SENSE ADJH TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS CX2 SENSE ADJH TEST:.................OK \n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(adjhor); + adjhor = NULL; + } else + logError(0, + "%s SS CX2 SENSE ADJ TEST:.................SKIPPED \n\n", + tag); + + + if (todo->SelfSenseCxTotal == 1 || todo->SelfSenseCxTotalAdj == 1) { + + if (todo->SelfSenseCxTotal == 1) { + logError(1, "%s SS TOTAL CX SENSE MIN MAX TEST: \n", tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_CX_SENSE_MAP_MIN, &thresholds_min, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MIN failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_CX_SENSE_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != totCompData.header.sense_node)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapTotal(totCompData.cx_sn, 1, totCompData.header.sense_node, thresholds_min, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMap SS TOTAL CX SENSE failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL CX SENSE MIN MAX TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL CX SENSE MIN MAX TEST:.................OK \n\n", + tag); + + kfree(thresholds_min); + thresholds_min = NULL; + kfree(thresholds_max); + thresholds_max = NULL; + } else + logError(0, + "%s SS TOTAL CX SENSE MIN MAX TEST:.................SKIPPED \n", + tag); + + + if (todo->SelfSenseCxTotalAdj == 1) { + logError(1, "%s SS TOTAL CX SENSE ADJHORIZ TEST: \n", + tag); + ret = + computeAdjHorizTotal(totCompData.cx_sn, 1, + totCompData.header.sense_node, + &total_adjhor); + + if (ret < 0) { + logError(1, + "%s production_test_data: computeAdjHoriz SS TOTAL CX SENSE ADJH failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + logError(0, + "%s SS TOTAL CX SENSE ADJ HORIZ computed! \n", + tag); + ret = parseProductionTestLimits(path_limits, &limit_file, SS_TOTAL_CX_SENSE_ADJH_MAP_MAX, &thresholds_max, &trows, &tcolumns); + + if (ret < 0 + || (trows != 1 + || tcolumns != + totCompData.header.sense_node - 1)) { + logError(1, + "%s production_test_data: parseProductionTestLimits SS_TOTAL_CX_SENSE_ADJH_MAP_MAX failed... ERROR %08X \n", + tag, ERROR_PROD_TEST_DATA); + ret |= ERROR_PROD_TEST_DATA; + goto ERROR_LIMITS; + } + + ret = checkLimitsMapAdjTotal(total_adjhor, 1, totCompData.header.sense_node - 1, thresholds_max); + + if (ret != OK) { + logError(1, + "%s production_test_data: checkLimitsMapAdj SS TOTAL CX SENSE ADJH failed... ERROR COUNT = %d \n", + tag, ret); + logError(0, + "%s SS TOTAL CX SENSE ADJH TEST:.................FAIL \n\n", + tag); + count_fail += 1; + + if (stop_on_fail) + goto ERROR; + } else + logError(0, + "%s SS TOTAL CX SENSE ADJH TEST:.................OK \n\n", + tag); + + kfree(thresholds_max); + thresholds_max = NULL; + kfree(total_adjhor); + total_adjhor = NULL; + } else + logError(0, + "%s SS TOTAL CX SENSE ADJ TEST:.................SKIPPED \n", + tag); + } else + logError(0, + "%s SS TOTAL CX SENSE TEST:.................SKIPPED \n", + tag); + if (todo->SelfHoverForceIxTotal == 1 || todo->SelfHoverSenceIxTotal == 1) { + ret = production_test_ss_hover_ix(path_limits, stop_on_fail, todo); + if (ret < OK) { + logError(1, + "%s production_test_data: production_test_ss_hover_ix_cx failed... ERROR = %08X\n", + tag, ret); + count_fail += 1; + } + } + +ERROR: + logError(0, "%s \n", tag); + + if (count_fail == 0) { + kfree(ssCompData.ix2_fm); + ssCompData.ix2_fm = NULL; + kfree(ssCompData.ix2_sn); + ssCompData.ix2_sn = NULL; + kfree(ssCompData.cx2_fm); + ssCompData.cx2_fm = NULL; + kfree(ssCompData.cx2_sn); + ssCompData.cx2_sn = NULL; + kfree(totCompData.ix_fm); + totCompData.ix_fm = NULL; + kfree(totCompData.ix_sn); + totCompData.ix_sn = NULL; + kfree(totCompData.cx_fm); + totCompData.cx_fm = NULL; + kfree(totCompData.cx_sn); + totCompData.cx_sn = NULL; + logError(0, + "%s SS IX CX testes finished!.................OK\n\n", + tag); + return OK; + } else { + print_frame_u8("SS Init Data Ix2_fm = ", + array1dTo2d_u8(ssCompData.ix2_fm, + ssCompData.header.force_node, 1), + ssCompData.header.force_node, 1); + print_frame_i8("SS Init Data Cx2_fm = ", + array1dTo2d_i8(ssCompData.cx2_fm, + ssCompData.header.force_node, 1), + ssCompData.header.force_node, 1); + print_frame_u8("SS Init Data Ix2_sn = ", + array1dTo2d_u8(ssCompData.ix2_sn, + ssCompData.header.sense_node, + ssCompData.header.sense_node), 1, + ssCompData.header.sense_node); + print_frame_i8("SS Init Data Cx2_sn = ", + array1dTo2d_i8(ssCompData.cx2_sn, + ssCompData.header.sense_node, + ssCompData.header.sense_node), 1, + ssCompData.header.sense_node); + print_frame_u16("TOT SS Init Data Ix_fm = ", + array1dTo2d_u16(totCompData.ix_fm, + totCompData.header.force_node, + 1), + totCompData.header.force_node, 1); + print_frame_short("TOT SS Init Data Cx_fm = ", + array1dTo2d_short(totCompData.cx_fm, + totCompData.header. + force_node, 1), + totCompData.header.force_node, 1); + print_frame_u16("TOT SS Init Data Ix_sn = ", + array1dTo2d_u16(totCompData.ix_sn, + totCompData.header.sense_node, + totCompData.header.sense_node), + 1, totCompData.header.sense_node); + print_frame_short("TOT SS Init Data Cx_sn = ", + array1dTo2d_short(totCompData.cx_sn, + totCompData.header. + sense_node, + totCompData.header. + sense_node), 1, + totCompData.header.sense_node); + logError(0, + "%s SS IX CX testes finished!.................FAILED fails_count = %d\n\n", + tag, count_fail); + + if (thresholds != NULL) + kfree(thresholds); + + if (thresholds_min != NULL) + kfree(thresholds_min); + + if (thresholds_max != NULL) + kfree(thresholds_max); + + if (adjhor != NULL) + kfree(adjhor); + + if (adjvert != NULL) + kfree(adjvert); + + if (total_adjhor != NULL) + kfree(total_adjhor); + + if (total_adjvert != NULL) + kfree(total_adjvert); + + if (ssCompData.ix2_fm != NULL) + kfree(ssCompData.ix2_fm); + + if (ssCompData.ix2_sn != NULL) + kfree(ssCompData.ix2_sn); + + if (ssCompData.cx2_fm != NULL) + kfree(ssCompData.cx2_fm); + + if (ssCompData.cx2_sn != NULL) + kfree(ssCompData.cx2_sn); + + if (totCompData.ix_fm != NULL) + kfree(totCompData.ix_fm); + + if (totCompData.ix_sn != NULL) + kfree(totCompData.ix_sn); + + if (totCompData.cx_fm != NULL) + kfree(totCompData.cx_fm); + + if (totCompData.cx_sn != NULL) + kfree(totCompData.cx_sn); + + return (ERROR_TEST_CHECK_FAIL | ERROR_PROD_TEST_DATA); + } + +ERROR_LIMITS: + + if (thresholds != NULL) + kfree(thresholds); + + if (thresholds_min != NULL) + kfree(thresholds_min); + + if (thresholds_max != NULL) + kfree(thresholds_max); + + if (adjhor != NULL) + kfree(adjhor); + + if (adjvert != NULL) + kfree(adjvert); + + if (total_adjhor != NULL) + kfree(total_adjhor); + + if (total_adjvert != NULL) + kfree(total_adjvert); + + if (ssCompData.ix2_fm != NULL) + kfree(ssCompData.ix2_fm); + + if (ssCompData.ix2_sn != NULL) + kfree(ssCompData.ix2_sn); + + if (ssCompData.cx2_fm != NULL) + kfree(ssCompData.cx2_fm); + + if (ssCompData.cx2_sn != NULL) + kfree(ssCompData.cx2_sn); + + if (totCompData.ix_fm != NULL) + kfree(totCompData.ix_fm); + + if (totCompData.ix_sn != NULL) + kfree(totCompData.ix_sn); + + if (totCompData.cx_fm != NULL) + kfree(totCompData.cx_fm); + + if (totCompData.cx_sn != NULL) + kfree(totCompData.cx_sn); + + return ret; +} + +/** + * Perform a complete Data Test check of the IC + * @param path_limits name of Production Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param stop_on_fail if 1, the test flow stops at the first data check failure otherwise it keeps going performing all the selected test + * @param todo pointer to a TestToDo variable which select the test to do + * @return OK if success or an error code which specify the type of error encountered + */ +int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo) +{ + int res = OK, ret; + + if (todo == NULL) { + logError(1, + "%s production_test_data: No TestToDo specified!! ERROR = %08X \n", + tag, (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA)); + return (ERROR_OP_NOT_ALLOW | ERROR_PROD_TEST_DATA); + } + + logError(1, "%s DATA Production test is starting...\n", tag); + ret = production_test_ms_raw(path_limits, stop_on_fail, todo); + res |= ret; + + if (ret < 0) { + logError(1, + "%s production_test_data: production_test_ms_raw failed... ERROR = %08X \n", + tag, ret); + + if (stop_on_fail == 1) + goto END; + } + + ret = production_test_ms_cx(path_limits, stop_on_fail, todo); + res |= ret; + + if (ret < 0) { + logError(1, + "%s production_test_data: production_test_ms_cx failed... ERROR = %08X \n", + tag, ret); + + if (stop_on_fail == 1) + goto END; + } + + ret = production_test_ss_raw(path_limits, stop_on_fail, todo); + res |= ret; + + if (ret < 0) { + logError(1, + "%s production_test_data: production_test_ss_raw failed... ERROR = %08X \n", + tag, ret); + + if (stop_on_fail == 1) + goto END; + } + + ret = production_test_ss_ix_cx(path_limits, stop_on_fail, todo); + res |= ret; + + if (ret < 0) { + logError(1, + "%s production_test_data: production_test_ss_ix_cx failed... ERROR = %08X \n", + tag, ret); + + if (stop_on_fail == 1) + goto END; + } + +END: + freeLimitsFile(&limit_file); + + if (res < OK) + logError(0, "%s DATA Production test failed!\n", tag); + else + logError(0, "%s DATA Production test finished!\n", tag); + + return res; +} + +/** + * Retrieve the actual Test Limit data from the system (bin file or header file) + * @param path name of Production Test Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param file pointer to the LimitFile struct which will contains the limits data + * @return OK if success or an error code which specify the type of error encountered + */ +int getLimitsFile(char *path, LimitFile *file) +{ + const struct firmware *fw = NULL; + struct device *dev = NULL; + int fd = -1; + logError(0, "%s Get Limits File starting... %s\n", tag, path); + + if (file->data != NULL) { + logError(0, + "%s Pointer to Limits Data already contains something... freeing its content!\n", + tag); + kfree(file->data); + file->data = NULL; + file->size = 0; + } + + strlcpy(file->name, path, MAX_LIMIT_FILE_NAME); + + if (strncmp(path, "NULL", 4) == 0) { +#ifdef LIMITS_H_FILE + logError(0, "%s Loading Limits File from .h!\n", tag); + file->size = LIMITS_SIZE_NAME; + file->data = + (char *)kmalloc((file->size) * sizeof(char), GFP_KERNEL); + + if (file->data != NULL) { + memcpy(file->data, (char *)(LIMITS_ARRAY_NAME), + file->size); + return OK; + } else { + logError(1, + "%s Error while allocating data... ERROR %08X \n", + tag, path, ERROR_ALLOC); + return ERROR_ALLOC; + } + +#else + logError(1, "%s limit file path NULL... ERROR %08X \n", tag, + ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; +#endif + } else { + dev = getDev(); + + if (dev != NULL) { + logError(0, "%s Loading Limits File from .csv!\n", tag); + fd = request_firmware(&fw, path, dev); + + if (fd == 0) { + logError(0, "%s Start to copy %s...\n", tag, + path); + file->size = fw->size; + file->data = + (char *)kmalloc((file->size) * sizeof(char), + GFP_KERNEL); + + if (file->data != NULL) { + memcpy(file->data, (char *)fw->data, + file->size); + logError(0, + "%s Limit file Size = %d \n", + tag, file->size); + release_firmware(fw); + return OK; + } else { + logError(1, + "%s Error while allocating data... ERROR %08X \n", + tag, path, ERROR_ALLOC); + release_firmware(fw); + return ERROR_ALLOC; + } + } else { + logError(1, + "%s Request the file %s failed... ERROR %08X \n", + tag, path, ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; + } + } else { + logError(1, + "%s Error while getting the device ERROR %08X \n", + tag, ERROR_FILE_READ); + return ERROR_FILE_READ; + } + } +} + +/** + * Reset and release the memory which store a Production Limit File previously loaded + * @param file pointer to the LimitFile struct to free + * @return OK if success or an error code which specify the type of error encountered + */ + +int freeLimitsFile(LimitFile *file) +{ + logError(0, "%s Freeing Limit File ...\n", tag); + + if (file != NULL) { + if (file->data != NULL) { + kfree(file->data); + file->data = NULL; + } else + logError(0, "%s Limit File was already freed!\n", tag); + + file->size = 0; + strlcpy(file->name, " ", MAX_LIMIT_FILE_NAME); + return OK; + } else { + logError(1, "%s Passed a NULL argument! ERROR %08X \n", tag, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } +} + +/** + * Reset and release the memory which store the current Limit File previously loaded + * @return OK if success or an error code which specify the type of error encountered + */ + +int freeCurrentLimitsFile(void) +{ + return freeLimitsFile(&limit_file); +} + +/** + * Parse the raw data read from a Production test limit file in order to find the specified information + * If no limits file data are passed, the function loads and stores the limit file from the system + * @param path name of Production Test Limit file to load or "NULL" if the limits data should be loaded by a .h file + * @param file pointer to LimitFile struct that should be parsed or NULL if the limit file in the system should be loaded and then parsed + * @param label string which identify a particular set of data in the file that want to be loaded + * @param data pointer to the pointer which will contains the specified limits data as 1 dimension matrix with data arranged row after row + * @param row pointer to a int variable which will contain the number of row of data + * @param column pointer to a int variable which will contain the number of column of data + * @return OK if success or an error code which specify the type of error encountered + */ +int parseProductionTestLimits(char *path, LimitFile *file, char *label, + int **data, int *row, int *column) +{ + int find = 0; + char *token = NULL; + int i = 0; + int j = 0; + int z = 0; + char *line2 = NULL; + char line[800]; + char *buf = NULL; + int n, size, pointer = 0, ret = OK; + char *data_file = NULL; + + if (file == NULL || strcmp(path, file->name) != 0 || file->size == 0) { + logError(0, + "%s No limit File data passed... try to get them from the system!\n", + tag); + ret = getLimitsFile(LIMITS_FILE, &limit_file); + + if (ret < OK) { + logError(1, + "%s parseProductionTestLimits: ERROR %08X\n", + tag, ERROR_FILE_NOT_FOUND); + return ERROR_FILE_NOT_FOUND; + } + + size = limit_file.size; + data_file = limit_file.data; + } else { + logError(0, "%s Limit File data passed as arguments!\n", tag); + size = file->size; + data_file = file->data; + } + + logError(0, "%s The size of the limits file is %d bytes...\n", tag, + size); + + while (find == 0) { + if (readLine(&data_file[pointer], line, size - pointer, &n) < 0) { + find = -1; + break; + } + + pointer += n; + + if (line[0] == '*') { + line2 = kstrdup(line, GFP_KERNEL); + + if (line2 == NULL) { + logError(1, + "%s parseProductionTestLimits: kstrdup ERROR %08X\n", + tag, ERROR_ALLOC); + ret = ERROR_ALLOC; + goto END; + } + + buf = line2; + line2 += 1; + token = strsep(&line2, ","); + + if (strcmp(token, label) == 0) { + find = 1; + token = strsep(&line2, ","); + + if (token != NULL) { + sscanf(token, "%d", row); + logError(0, "%s Row = %d\n", tag, *row); + } else { + logError(1, + "%s parseProductionTestLimits 1: ERROR %08X\n", + tag, ERROR_FILE_PARSE); + ret = ERROR_FILE_PARSE; + goto END; + } + + token = strsep(&line2, ","); + + if (token != NULL) { + sscanf(token, "%d", column); + logError(0, "%s Column = %d\n", tag, + *column); + } else { + logError(1, + "%s parseProductionTestLimits 2: ERROR %08X\n", + tag, ERROR_FILE_PARSE); + ret = ERROR_FILE_PARSE; + goto END; + } + + kfree(buf); + buf = NULL; + *data = (int *)kmalloc(((*row) * (*column)) * sizeof(int), GFP_KERNEL); + j = 0; + + if (*data == NULL) { + logError(1, + "%s parseProductionTestLimits: ERROR %08X\n", + tag, ERROR_ALLOC); + ret = ERROR_ALLOC; + goto END; + } + + for (i = 0; i < *row; i++) { + if (readLine + (&data_file[pointer], line, + size - pointer, &n) < 0) { + logError(1, + "%s parseProductionTestLimits : ERROR %08X\n", + tag, ERROR_FILE_READ); + ret = ERROR_FILE_READ; + goto END; + } + + pointer += n; + line2 = kstrdup(line, GFP_KERNEL); + + if (line2 == NULL) { + logError(1, + "%s parseProductionTestLimits: kstrdup ERROR %08X\n", + tag, ERROR_ALLOC); + ret = ERROR_ALLOC; + goto END; + } + + buf = line2; + token = strsep(&line2, ","); + + for (z = 0; + (z < *column) && (token != NULL); + z++) { + sscanf(token, "%d", + ((*data) + j)); + j++; + token = strsep(&line2, ","); + } + + kfree(buf); + buf = NULL; + } + + if (j == ((*row) * (*column))) { + logError(0, "%s READ DONE!\n", tag); + ret = OK; + goto END; + } + + logError(1, + "%s parseProductionTestLimits 3: ERROR %08X\n", + tag, ERROR_FILE_PARSE); + ret = ERROR_FILE_PARSE; + goto END; + } + + kfree(buf); + buf = NULL; + } + } + + logError(1, "%s parseProductionTestLimits: ERROR %08X\n", tag, + ERROR_LABEL_NOT_FOUND); + ret = ERROR_LABEL_NOT_FOUND; +END: + + if (buf != NULL) + kfree(buf); + + return ret; +} + +/** + * Read one line of a text file passed as array of byte and terminate it with a termination character '\0' + * @param data text file as array of bytes + * @param line pointer to an array of char that will contain the line read + * @param size size of data + * @param n pointer to a int variable which will contain the number of characters of the line + * @return OK if success or an error code which specify the type of error encountered + */ +int readLine(char *data, char *line, int size, int *n) +{ + int i = 0; + + if (size < 1) + return -EINVAL; + + while (data[i] != '\n' && i < size) { + line[i] = data[i]; + i++; + } + + *n = i + 1; + line[i] = '\0'; + return OK; +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsTest.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsTest.h new file mode 100644 index 000000000000..127dce0478ee --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsTest.h @@ -0,0 +1,293 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS API for MP test * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsTest.h +* \brief Contains all the definitions and structs related to the Mass Production Test +*/ + +#ifndef FTS_TEST_H +#define FTS_TEST_H + +#include "ftsSoftware.h" + +#ifndef LIMITS_H_FILE +#define LIMITS_FILE "stm_fts_production_limits.csv" /*Name of the Production Test Limit File*/ +#else +#define LIMITS_FILE "NULL" +#endif + +#define WAIT_FOR_FRESH_FRAMES 200 /*Time in ms to wait after start to sensing before reading a frame*/ +#define WAIT_AFTER_SENSEOFF 50 /*Time in ms to wait after stop sensing and before reading a frame from memory*/ + +#define NO_INIT 0 /*No Initialization required during the MP*/ + +#define RETRY_INIT_BOOT 3 /*number of retry of the initialization process at boot*/ + +/** @defgroup mp_test Mass Production Test + * Mass production test API. + * Mass Production Test (MP) should be executed at least one time in the life of every device \n + * It used to verify that tit is not present any hardware damage and initialize some value of the chip in order to guarantee the working performance \n + * The MP test is made up by 3 steps: + * - ITO test = production_test_ito() \n + * - Initialization = production_test_initialization() \n + * - Data Test = production_test_data(), it is possible to select which items test thanks to the TestToDo struct\n + * To execute the Data Test it is mandatory load some thresholds that are stored in the Limit File. + * @{ + */ + +/** @defgroup limit_file Limit File + * @ingroup mp_test + * Production Test Limit File is a csv which contains thresholds of the data to test. + * This file can be loaded from the file system or stored as a header file according to the LIMITS_H_FILE define \n + * For each selectable test item there can be one or more associated labels which store the corresponding thresholds \n + * @{ + */ + +/** @defgroup test_labels Test Items Labels + * @ingroup limit_file + * Labels present in the Limit File and associated to the test items of TestToDo + * @{ + */ +#define MS_RAW_MIN_MAX "MS_RAW_DATA_MIN_MAX" +#define MS_RAW_EACH_NODE_MIN "MS_RAW_DATA_EACH_MIN" +#define MS_RAW_EACH_NODE_MAX "MS_RAW_DATA_EACH_MAX" +#define MS_RAW_GAP "MS_RAW_DATA_GAP" +#define MS_RAW_ADJH "MS_RAW_DATA_ADJ_HORIZONTAL" +#define MS_RAW_ADJV "MS_RAW_DATA_ADJ_VERTICAL" +#define MS_RAW_ITO_ADJH "MS_RAW_ITO_DATA_ADJ_HORIZONTAL" +#define MS_RAW_ITO_ADJV "MS_RAW_ITO_DATA_ADJ_VERTICAL" +#define MS_RAW_LP_MIN_MAX "MS_RAW_LOWPOWER_DATA_MIN_MAX" +#define MS_RAW_LP_GAP "MS_RAW_LOWPOWER_DATA_GAP" +#define MS_RAW_LP_ADJH "MS_RAW_LOWPOWER_DATA_ADJ_HORIZONTAL" +#define MS_RAW_LP_ADJV "MS_RAW_LOWPOWER_DATA_ADJ_VERTICAL" +#define MS_CX1_MIN_MAX "MS_TOUCH_ACTIVE_CX1_MIN_MAX" +#define MS_CX2_MAP_MIN "MS_TOUCH_ACTIVE_CX2_MIN" +#define MS_CX2_MAP_MAX "MS_TOUCH_ACTIVE_CX2_MAX" +#define MS_CX2_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL" +#define MS_CX2_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL" +#define MS_TOTAL_CX_MAP_MIN "MS_TOUCH_ACTIVE_TOTAL_CX_MIN" +#define MS_TOTAL_CX_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_MAX" +#define MS_TOTAL_CX_ADJH_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL" +#define MS_TOTAL_CX_ADJV_MAP_MAX "MS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL" +#define MS_CX1_LP_MIN_MAX "MS_TOUCH_LOWPOWER_CX1_MIN_MAX" +#define MS_CX2_LP_MAP_MIN "MS_TOUCH_LOWPOWER_CX2_MIN" +#define MS_CX2_LP_MAP_MAX "MS_TOUCH_LOWPOWER_CX2_MAX" +#define MS_CX2_ADJH_LP_MAP_MAX "MS_TOUCH_LOWPOWER_CX2_ADJ_HORIZONTAL" +#define MS_CX2_ADJV_LP_MAP_MAX "MS_TOUCH_LOWPOWER_CX2_ADJ_VERTICAL" +#define MS_TOTAL_CX_LP_MAP_MIN "MS_TOUCH_LOWPOWER_TOTAL_CX_MIN" +#define MS_TOTAL_CX_LP_MAP_MAX "MS_TOUCH_LOWPOWER_TOTAL_CX_MAX" +#define MS_TOTAL_CX_ADJH_LP_MAP_MAX "MS_TOUCH_LOWPOWER_TOTAL_CX_ADJ_HORIZONTAL" +#define MS_TOTAL_CX_ADJV_LP_MAP_MAX "MS_TOUCH_LOWPOWER_TOTAL_CX_ADJ_VERTICAL" +#define SS_RAW_FORCE_MIN_MAX "SS_RAW_DATA_FORCE_MIN_MAX" +#define SS_RAW_SENSE_MIN_MAX "SS_RAW_DATA_SENSE_MIN_MAX" +#define SS_RAW_FORCE_GAP "SS_RAW_DATA_FORCE_GAP" +#define SS_RAW_SENSE_GAP "SS_RAW_DATA_SENSE_GAP" +#define SS_RAW_LP_FORCE_MIN_MAX "SS_RAW_LOWPOWER_DATA_FORCE_MIN_MAX" +#define SS_RAW_LP_SENSE_MIN_MAX "SS_RAW_LOWPOWER_DATA_SENSE_MIN_MAX" +#define SS_RAW_LP_FORCE_GAP "SS_RAW_LOWPOWER_DATA_FORCE_GAP" +#define SS_RAW_LP_SENSE_GAP "SS_RAW_LOWPOWER_DATA_SENSE_GAP" +#define SS_IX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_FORCE_MIN_MAX" +#define SS_IX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_IX1_SENSE_MIN_MAX" +#define SS_CX1_FORCE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_FORCE_MIN_MAX" +#define SS_CX1_SENSE_MIN_MAX "SS_TOUCH_ACTIVE_CX1_SENSE_MIN_MAX" +#define SS_IX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_FORCE_MIN" +#define SS_IX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_FORCE_MAX" +#define SS_IX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_IX2_SENSE_MIN" +#define SS_IX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_IX2_SENSE_MAX" +#define SS_IX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_VERTICAL" +#define SS_IX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_IX2_ADJ_HORIZONTAL" +#define SS_CX2_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_FORCE_MIN" +#define SS_CX2_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_FORCE_MAX" +#define SS_CX2_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_CX2_SENSE_MIN" +#define SS_CX2_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_CX2_SENSE_MAX" +#define SS_CX2_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_VERTICAL" +#define SS_CX2_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_CX2_ADJ_HORIZONTAL" + +#define SS_TOTAL_IX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MIN" +#define SS_TOTAL_IX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_FORCE_MAX" +#define SS_TOTAL_IX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MIN" +#define SS_TOTAL_IX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_SENSE_MAX" +#define SS_TOTAL_IX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_VERTICAL" +#define SS_TOTAL_IX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_IX_ADJ_HORIZONTAL" +#define SS_TOTAL_CX_FORCE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MIN" +#define SS_TOTAL_CX_FORCE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_FORCE_MAX" +#define SS_TOTAL_CX_SENSE_MAP_MIN "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MIN" +#define SS_TOTAL_CX_SENSE_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_SENSE_MAX" +#define SS_TOTAL_CX_FORCE_ADJV_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_VERTICAL" +#define SS_TOTAL_CX_SENSE_ADJH_MAP_MAX "SS_TOUCH_ACTIVE_TOTAL_CX_ADJ_HORIZONTAL" + +#define MS_KEY_RAW_MIN_MAX "MS_KEY_RAW_DATA_MIN_MAX" +#define MS_KEY_CX1_MIN_MAX "MS_KEY_CX1_MIN_MAX" +#define MS_KEY_CX2_MAP_MIN "MS_KEY_CX2_MIN" +#define MS_KEY_CX2_MAP_MAX "MS_KEY_CX2_MAX" +#define MS_KEY_TOTAL_CX_MAP_MIN "MS_KEY_TOTAL_CX_MIN" +#define MS_KEY_TOTAL_CX_MAP_MAX "MS_KEY_TOTAL_CX_MAX" + +#define SS_IX1_FORCE_W "IX1_FORCE_W" +#define SS_IX2_FORCE_W "IX2_FORCE_W" +#define SS_IX1_SENSE_W "IX1_SENSE_W" +#define SS_IX2_SENSE_W "IX2_SENSE_W" + +/* SS HOVER*/ +#define SS_HOVER_RAW_FORCE_MIN_MAX "SS_RAW_HOVER_DATA_FORCE_MIN_MAX" +#define SS_HOVER_TOTAL_IX_FORCE_MAP_MIN "SS_HOVER_TOTAL_IX_FORCE_MIN" +#define SS_HOVER_TOTAL_IX_FORCE_MAP_MAX "SS_HOVER_TOTAL_IX_FORCE_MAX" +#define SS_HOVER_RAW_SENSE_MIN_MAX "SS_RAW_HOVER_DATA_SENSE_MIN_MAX" +#define SS_HOVER_TOTAL_IX_SENSE_MAP_MIN "SS_HOVER_TOTAL_IX_SENSE_MIN" +#define SS_HOVER_TOTAL_IX_SENSE_MAP_MAX "SS_HOVER_TOTAL_IX_SENSE_MAX" + +/** @}*/ + +/** +* Struct used to specify which test perform during the Mass Production Test. +* For each test item selected in this structure, there should be one or more labels associated in the Limit file from where load the thresholds +*/ +typedef struct { + int MutualRaw; /*MS Raw min/Max test*/ + int MutualRawEachNode; + int MutualRawGap; /*MS Raw Gap(max-min) test*/ + int MutualRawAdj; /*MS Raw Adjacent test*/ + int MutualRawLP; /*MS Low Power Raw min/Max test*/ + int MutualRawGapLP; /*MS Low Power Raw Gap(max-min) test*/ + int MutualRawAdjLP; /*MS Low Power Raw Adjacent test*/ + int MutualRawAdjITO; /*MS Raw Adjacent test during ITO test*/ + + int MutualCx1; /*MS Cx1 min/Max test*/ + int MutualCx2; /*MS Cx2 min/Max (for each node) test*/ + int MutualCx2Adj; /*MS Vertical and Horizontal Adj Cx2 min/Max (for each node) test*/ + int MutualCxTotal; /*MS Total Cx min/Max (for each node) test*/ + int MutualCxTotalAdj; /*MS Total vertical and Horizontal Adj Cx2 min/Max (for each node) test*/ + int MutualCx1LP; /* /< MS LowPower Cx1 min/Max test */ + int MutualCx2LP; /* /< MS LowPower Cx2 min/Max (for each node) test */ + int MutualCx2AdjLP; /* /< MS LowPower Vertical and Horizontal Adj Cx2 min/Max + * (for each node) test */ + int MutualCxTotalLP; /* /< MS Total LowPower Cx min/Max (for each node) test + * */ + int MutualCxTotalAdjLP; /* /< MS Total LowPower vertical and Horizontal Adj Cx2 + * min/Max (for each node) test */ + + int MutualKeyRaw; /*MS Raw Key min/Max test*/ + int MutualKeyCx1; /*MS Cx1 Key min/Max test*/ + int MutualKeyCx2; /*MS Cx2 Key min/Max (for each node) test*/ + int MutualKeyCxTotal; /*MS Total Cx Key min/Max (for each node) test*/ + + int SelfHoverForceRaw; /* SS Hover Force Raw min/Max test */ + int SelfHoverSenceRaw; /*SS Hover Sence Raw min/Max test */ + int SelfHoverForceIxTotal; /*SS Hover Total Force Ix min/Max (for each node)* test */ + int SelfHoverSenceIxTotal; /*SS Hover Total Sence Ix min/Max (for each node)* test */ + + int SelfForceRaw; /*SS Force Raw min/Max test*/ + int SelfForceRawGap; /*SS Force Raw Gap(max-min) test*/ + int SelfForceRawLP; /*SS Low Power Force Raw min/Max test*/ + int SelfForceRawGapLP; /*SS Low Power Force Raw Gap(max-min) test*/ + + int SelfForceIx1; /*SS Force Ix1 min/Max test*/ + int SelfForceIx2; /*SS Force Ix2 min/Max (for each node) test*/ + int SelfForceIx2Adj; /*SS Vertical Adj Force Ix2 min/Max (for each node) test*/ + int SelfForceIxTotal; /*SS Total Force Ix min/Max (for each node) test*/ + int SelfForceIxTotalAdj; /*SS Total Vertical Adj Force Ix min/Max (for each node) test*/ + int SelfForceCx1; /*SS Force Cx1 min/Max test*/ + int SelfForceCx2; /*SS Force Cx2 min/Max (for each node) test*/ + int SelfForceCx2Adj; /*SS Vertical Adj Force Cx2 min/Max (for each node) test*/ + int SelfForceCxTotal; /*SS Total Force Cx min/Max (for each node) test*/ + int SelfForceCxTotalAdj; /*SS Total Vertical Adj Force Cx min/Max (for each node) test*/ + + int SelfSenseRaw; /*SS Sense Raw min/Max test*/ + int SelfSenseRawGap; /*SS Sense Raw Gap(max-min) test*/ + int SelfSenseRawLP; /*SS Low Power Sense Raw min/Max test*/ + int SelfSenseRawGapLP; /*SS Low Power Sense Raw Gap(max-min) test*/ + + int SelfSenseIx1; /*SS Sense Ix1 min/Max test*/ + int SelfSenseIx2; /*SS Sense Ix2 min/Max (for each node) test*/ + int SelfSenseIx2Adj; /*SS Horizontal Adj Sense Ix2 min/Max (for each node) test*/ + int SelfSenseIxTotal; /*SS Total Horizontal Sense Ix min/Max (for each node) test*/ + int SelfSenseIxTotalAdj; /*SS Total Horizontal Adj Sense Ix min/Max (for each node) test*/ + int SelfSenseCx1; /*SS Sense Cx1 min/Max test*/ + int SelfSenseCx2; /*SS Sense Cx2 min/Max (for each node) test*/ + int SelfSenseCx2Adj; /*SS Horizontal Adj Sense Cx2 min/Max (for each node) test*/ + int SelfSenseCxTotal; /*SS Total Sense Cx min/Max (for each node) test*/ + int SelfSenseCxTotalAdj; /*SS Total Horizontal Adj Sense Cx min/Max (for each node) test*/ + +} TestToDo; + +#define MAX_LIMIT_FILE_NAME 100 /*max number of chars of the limit file name*/ + +/** + * Struct which store the data coming from a Production Limit File + */ +typedef struct { + char *data; + int size; + char name[MAX_LIMIT_FILE_NAME]; +} LimitFile; + +int initTestToDo(void); +/**@}*/ + +/**@}*/ + +int computeAdjHoriz(i8 *data, int row, int column, u8 **result); +int computeAdjHorizTotal(short *data, int row, int column, u16 **result); +int computeAdjVert(i8 *data, int row, int column, u8 **result); +int computeAdjVertTotal(short *data, int row, int column, u16 **result); +int computeAdjHorizFromU(u8 *data, int row, int column, u8 **result); +int computeAdjHorizTotalFromU(u16 *data, int row, int column, u16 **result); +int computeAdjVertFromU(u8 *data, int row, int column, u8 **result); +int computeAdjVertTotalFromU(u16 *data, int row, int column, u16 **result); +int checkLimitsMinMax(short *data, int row, int column, int min, int max); +int checkLimitsMap(i8 *data, int row, int column, int *min, int *max); +int checkLimitsMapTotal(short *data, int row, int column, int *min, int *max); +int checkLimitsMapFromU(u8 *data, int row, int column, int *min, int *max); +int checkLimitsMapTotalFromU(u16 *data, int row, int column, int *min, + int *max); +int checkLimitsMapAdj(u8 *data, int row, int column, int *max); +int checkLimitsMapAdjTotal(u16 *data, int row, int column, int *max); + +/** @defgroup mp_api MP API + * @ingroup mp_test + * Functions to execute the MP test. + * The parameters of these functions allow to customize their behavior in order to satisfy different scenarios + * @{ + */ +int production_test_ito(char *path_limits, TestToDo *todo); +int production_test_initialization(u8 type); +int production_test_main(char *pathThresholds, int stop_on_fail, int saveInit, TestToDo *todo); +int production_test_ms_raw(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ms_raw_lp(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ms_cx(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ms_cx_lp(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ss_raw(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ss_raw_lp(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ss_ix_cx(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_data(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ms_key_cx(char *path_limits, int stop_on_fail, TestToDo *todo); +int production_test_ms_key_raw(char *path_limits); +int computeTotal(u8 *data, u8 main, int row, int column, int m, int n, + u16 **result); +/** @}*/ + +/** + * @addtogroup limit_file + * @{ + */ +int parseProductionTestLimits(char *path, LimitFile *file, char *label, int **data, int *row, int *column); +int readLine(char *data, char *line, int size, int *n); +int getLimitsFile(char *path, LimitFile *file); +int freeLimitsFile(LimitFile *file); +int freeCurrentLimitsFile(void); +/**@}*/ + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsTime.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsTime.c new file mode 100644 index 000000000000..1752ea22d483 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsTime.c @@ -0,0 +1,80 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS Utility for mesuring/handling the time * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsTime.c +* \brief Contains all functions to handle and measure the time in the driver +*/ + +#include "ftsTime.h" + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/** +* Take the starting time and save it in a StopWatch variable +* @param w pointer of a StopWatch struct +*/ +void startStopWatch(StopWatch *w) +{ + w->start = current_kernel_time(); +} + +/** +* Take the stop time and save it in a StopWatch variable +* @param w pointer of a StopWatch struct +*/ +void stopStopWatch(StopWatch *w) +{ + w->end = current_kernel_time(); +} + +/** +* Compute the amount of time spent from when the startStopWatch and then the stopStopWatch were called on the StopWatch variable +* @param w pointer of a StopWatch struct +* @return amount of time in ms (the return value is meaningless if the startStopWatch and stopStopWatch were not called before) +*/ +int elapsedMillisecond(StopWatch *w) +{ + int result; + + result = + ((w->end.tv_sec - w->start.tv_sec) * 1000) + (w->end.tv_nsec - + w->start.tv_nsec) / 1000000; + return result; +} + +/** +* Compute the amount of time spent from when the startStopWatch and then the stopStopWatch were called on the StopWatch variable +* @param w pointer of a StopWatch struct +* @return amount of time in ns (the return value is meaningless if the startStopWatch and stopStopWatch were not called before) +*/ +int elapsedNanosecond(StopWatch *w) +{ + int result; + + result = + ((w->end.tv_sec - w->start.tv_sec) * 1000000000) + (w->end.tv_nsec - + w->start.tv_nsec); + return result; +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsTime.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsTime.h new file mode 100644 index 000000000000..7f0592318f4c --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsTime.h @@ -0,0 +1,54 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS Utility for measuring/handling the time * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsTime.h +* \brief Contains all the definitions and structs to handle and measure the time in the driver +*/ + +#ifndef FTS_TIME_H +#define FTS_TIME_H + +#include + +/** @defgroup timeouts Timeouts +* Definitions of all the Timeout used in several operations +* @{ +*/ +#define TIMEOUT_RESOLUTION 2 /*timeout resolution in ms (all timeout should be multiples of this unit)*/ +#define GENERAL_TIMEOUT (50 * TIMEOUT_RESOLUTION) /*general timeout in ms*/ +#define RELEASE_INFO_TIMEOUT (15 * TIMEOUT_RESOLUTION) /* timeout to request release info in ms*/ + +#define TIMEOUT_REQU_COMP_DATA (100 * TIMEOUT_RESOLUTION) /*timeout to request compensation data in ms*/ +#define TIMEOUT_REQU_DATA (100 * TIMEOUT_RESOLUTION) /*timeout to request data in ms*/ +#define TIMEOUT_ITO_TEST_RESULT (100 * TIMEOUT_RESOLUTION) /*timeout to perform ito test in ms*/ +#define TIMEOUT_INITIALIZATION_TEST_RESULT (5000 * TIMEOUT_RESOLUTION) /*timeout to perform initialization test in ms*/ +#define TIMEOUT_ECHO TIMEOUT_INITIALIZATION_TEST_RESULT /*timeout of the echo command, should be the max of all the possible commands (used in worst case)*/ +/** @}*/ + +/** +* Struct used to measure the time elapsed between a starting and ending point. +*/ +typedef struct { + struct timespec start; /*store the starting time*/ + struct timespec end; /*store the finishing time*/ +} StopWatch; + +void startStopWatch(StopWatch *w); +void stopStopWatch(StopWatch *w); +int elapsedMillisecond(StopWatch *w); +int elapsedNanosecond(StopWatch *w); + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsTool.c b/drivers/input/touchscreen/fts_521/fts_lib/ftsTool.c new file mode 100644 index 000000000000..ff99720fa5eb --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsTool.c @@ -0,0 +1,648 @@ +/* + + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * FTS Utility Functions * + * * + ************************************************************************** + ************************************************************************** + + */ + +/*! +* \file ftsTool.c +* \brief Contains all the functions to support common operation inside the driver +*/ + +#include "ftsCompensation.h" +#include "ftsCore.h" +#include "ftsError.h" +#include "ftsHardware.h" +#include "ftsIO.h" +#include "ftsSoftware.h" +#include "ftsTime.h" +#include "ftsTool.h" +#include "../fts.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/** +* Print an array of byte in a HEX string and attach at the beginning a label. The function allocate memory that should be free outside the function itself +* @param label string to attach at the beginning +* @param buff pointer to the byte array that should be printed as HEX string +* @param count size of buff +* @return pointer to the array of characters that compose the HEX string. This point should be free outside when the string is no more needed +*/ +char *printHex(char *label, u8 *buff, int count, u8 *result) +{ + int i, offset; + + offset = strlen(label); + + strlcpy(result, label, offset); + + for (i = 0; i < count; i++) { + snprintf(&result[offset], 4, "%02X ", buff[i]); + offset += 3; + } + + return result; +} + +char *printHex_data(char *label, u8 *buff, int count) +{ + int i, offset; + char *result = NULL; + + offset = strlen(label); + result = + (char *)kmalloc(((offset + 4 * count) + 1) * sizeof(char), + GFP_KERNEL); + if (result != NULL) { + strlcpy(result, label, offset); + + for (i = 0; i < count; i++) { + snprintf(&result[offset], 4, "%02X ", buff[i]); + offset += 3; + } + + strlcat(result, "\n", ((offset + 4 * count) + 1) * sizeof(char)); + } + return result; +} + +/** + * Clear the FIFO from any event + * @return OK if success or an error code which specify the type of error encountered + */ +int flushFIFO(void) +{ + + int ret; + u8 sett = SPECIAL_FIFO_FLUSH; + ret = writeSysCmd(SYS_CMD_SPECIAL, &sett, 1); + if (ret < OK) { + logError(1, "%s flushFIFO: ERROR %08X \n", tag, ret); + return ret; + } + + logError(0, "%s FIFO flushed! \n", tag); + return OK; + +} + +/** +* Convert an array of bytes to an array of u16 taking two bytes at time, src has LSB first. +* @param src pointer to the source byte array +* @param src_length size of src +* @param dst pointer to the destination array. +* @return the final size of dst (half of the source) or ERROR_OP_NOT_ALLOW if the size of src is not multiple of 2. +*/ +int u8ToU16n(u8 *src, int src_length, u16 *dst) +{ + int i, j; + + if (src_length % 2 != 0) { + return ERROR_OP_NOT_ALLOW; + } else { + j = 0; + dst = + (u16 *) kmalloc((src_length / 2) * sizeof(u16), GFP_KERNEL); + for (i = 0; i < src_length; i += 2) { + dst[j] = + ((src[i + 1] & 0x00FF) << 8) + (src[i] & 0x00FF); + j++; + } + } + + return (src_length / 2); +} + +/** +* Convert an array of 2 bytes to a u16, src has LSB first (little endian). +* @param src pointer to the source byte array +* @param dst pointer to the destination u16. +* @return OK +*/ +int u8ToU16(u8 *src, u16 *dst) +{ + *dst = (u16) (((src[1] & 0x00FF) << 8) + (src[0] & 0x00FF)); + return OK; +} + +/** +* Convert an array of 2 bytes to a u16, src has MSB first (big endian). +* @param src pointer to the source byte array +* @param dst pointer to the destination u16. +* @return OK +*/ +int u8ToU16_be(u8 *src, u16 *dst) +{ + *dst = (u16) (((src[0] & 0x00FF) << 8) + (src[1] & 0x00FF)); + return OK; +} + +/** +* Convert an array of u16 to an array of u8, dst has MSB first (big endian). +* @param src pointer to the source array of u16 +* @param src_length size of src +* @param dst pointer to the destination array of u8. This array should be free when no need anymore +* @return size of dst (src size multiply by 2) +*/ +int u16ToU8n_be(u16 *src, int src_length, u8 *dst) +{ + int i, j; + dst = (u8 *) kmalloc((2 * src_length) * sizeof(u8), GFP_KERNEL); + j = 0; + for (i = 0; i < src_length; i++) { + dst[j] = (u8) (src[i] & 0xFF00) >> 8; + dst[j + 1] = (u8) (src[i] & 0x00FF); + j += 2; + } + + return src_length * 2; +} + +/** +* Convert a u16 to an array of 2 u8, dst has MSB first (big endian). +* @param src u16 to convert +* @param dst pointer to the destination array of 2 u8. +* @return OK +*/ +int u16ToU8_be(u16 src, u8 *dst) +{ + dst[0] = (u8) ((src & 0xFF00) >> 8); + dst[1] = (u8) (src & 0x00FF); + return OK; +} + +/** +* Convert a u16 to an array of 2 u8, dst has LSB first (little endian). +* @param src u16 to convert +* @param dst pointer to the destination array of 2 u8. +* @return OK +*/ +int u16ToU8(u16 src, u8 *dst) +{ + dst[1] = (u8) ((src & 0xFF00) >> 8); + dst[0] = (u8) (src & 0x00FF); + return OK; +} + +/** +* Convert an array of bytes to a u32, src has LSB first (little endian). +* @param src array of bytes to convert +* @param dst pointer to the destination u32 variable. +* @return OK +*/ +int u8ToU32(u8 *src, u32 *dst) +{ + *dst = + (u32) (((src[3] & 0xFF) << 24) + ((src[2] & 0xFF) << 16) + + ((src[1] & 0xFF) << 8) + (src[0] & 0xFF)); + return OK; +} + +/** +* Convert a u32 to an array of 4 bytes, dst has LSB first (little endian). +* @param src u32 value to convert +* @param dst pointer to the destination array of 4 bytes. +* @return OK +*/ +int u32ToU8(u32 src, u8 *dst) +{ + dst[3] = (u8) ((src & 0xFF000000) >> 24); + dst[2] = (u8) ((src & 0x00FF0000) >> 16); + dst[1] = (u8) ((src & 0x0000FF00) >> 8); + dst[0] = (u8) (src & 0x000000FF); + return OK; +} + +/** +* Convert a u32 to an array of 4 bytes, dst has MSB first (big endian). +* @param src u32 value to convert +* @param dst pointer to the destination array of 4 bytes. +* @return OK +*/ +int u32ToU8_be(u32 src, u8 *dst) +{ + dst[0] = (u8) ((src & 0xFF000000) >> 24); + dst[1] = (u8) ((src & 0x00FF0000) >> 16); + dst[2] = (u8) ((src & 0x0000FF00) >> 8); + dst[3] = (u8) (src & 0x000000FF); + return OK; +} + +/** +* Execute a function passed as argment and retry it defined number of times if not successfull +* @param code pointer to a function which return an int and doesn't have any parameters +* @param wait_before_retry interval of time in ms to wait between one trial and another one +* @param retry_count max number of retry to attemp +* @return last return value obtained from the last execution of the code function +*/ +int attempt_function(int (*code) (void), unsigned long wait_before_retry, + int retry_count) +{ + int result; + int count = 0; + + do { + result = code(); + count++; + mdelay(wait_before_retry); + } while (count < retry_count && result < 0); + + if (count == retry_count) + return (result | ERROR_TIMEOUT); + else + return result; + +} + +/** + * Enable all the possible sensing mode supported by the FW + * @return OK if success or an error code which specify the type of error encountered + */ +int senseOn(void) +{ + int ret; + + ret = setScanMode(SCAN_MODE_ACTIVE, 0x01); + if (ret < OK) { + logError(1, "%s senseOn: ERROR %08X\n", tag, ret); + return ret; + } + + logError(0, "%s senseOn: SENSE ON\n", tag); + return OK; +} + +/** + * Disable all the sensing mode + * @return OK if success or an error code which specify the type of error encountered + */ +int senseOff(void) +{ + int ret; + + ret = setScanMode(SCAN_MODE_ACTIVE, 0x00);; + if (ret < OK) { + logError(1, "%s senseOff: ERROR %08X\n", tag, ret); + return ret; + } + + logError(0, "%s senseOff: SENSE OFF\n", tag); + return OK; +} + +/** + * Clean up the IC status executing a system reset and giving the possibility to re-enabling the sensing + * @param enableTouch if 1, re-enable the sensing and the interrupt of the IC + * @return OK if success or an error code which specify the type of error encountered + */ +int cleanUp(int enableTouch) +{ + int res; + + logError(0, "%s cleanUp: system reset...\n", tag); + res = fts_system_reset(); + if (res < OK) + return res; + if (enableTouch) { + logError(0, "%s cleanUp: enabling touches...\n", tag); + res = senseOn(); + if (res < OK) + return res; + logError(0, "%s cleanUp: enabling interrupts...\n", tag); + res = fts_enableInterrupt(); + if (res < OK) + return res; + } + return OK; + +} + +/** +* Transform an array of short in a matrix of short with a defined number of columns and the resulting number of rows +* @param data array of bytes to convert +* @param size size of data +* @param columns number of columns that the resulting matrix should have. +* @return a reference to a matrix of short where for each row there are columns elements +*/ +short **array1dTo2d_short(short *data, int size, int columns) +{ + + int i; + short **matrix = + (short **)kmalloc(((int)(size / columns)) * sizeof(short *), + GFP_KERNEL); + if (matrix != NULL) { + for (i = 0; i < (int)(size / columns); i++) { + matrix[i] = + (short *)kmalloc(columns * sizeof(short), + GFP_KERNEL); + } + + for (i = 0; i < size; i++) { + matrix[i / columns][i % columns] = data[i]; + } + } + + return matrix; +} + +/** +* Transform an array of u16 in a matrix of u16 with a defined number of columns and the resulting number of rows +* @param data array of bytes to convert +* @param size size of data +* @param columns number of columns that the resulting matrix should have. +* @return a reference to a matrix of u16 where for each row there are columns elements +*/ +u16 **array1dTo2d_u16(u16 *data, int size, int columns) +{ + + int i; + u16 **matrix = (u16 **) kmalloc(((int)(size / columns)) * sizeof(u16 *), + GFP_KERNEL); + if (matrix != NULL) { + for (i = 0; i < (int)(size / columns); i++) { + matrix[i] = + (u16 *) kmalloc(columns * sizeof(u16), GFP_KERNEL); + } + + for (i = 0; i < size; i++) { + matrix[i / columns][i % columns] = data[i]; + } + } + + return matrix; +} + +/** +* Transform an array of u8 in a matrix of u8 with a defined number of columns and the resulting number of rows +* @param data array of bytes to convert +* @param size size of data +* @param columns number of columns that the resulting matrix should have. +* @return a reference to a matrix of short where for each row there are columns elements +*/ +u8 **array1dTo2d_u8(u8 *data, int size, int columns) +{ + + int i; + u8 **matrix = + (u8 **) kmalloc(((int)(size / columns)) * sizeof(u8 *), GFP_KERNEL); + if (matrix != NULL) { + for (i = 0; i < (int)(size / columns); i++) { + matrix[i] = + (u8 *) kmalloc(columns * sizeof(u8), GFP_KERNEL); + } + + for (i = 0; i < size; i++) { + matrix[i / columns][i % columns] = data[i]; + } + } + + return matrix; +} + +/** +* Transform an array of i8 in a matrix of i8 with a defined number of columns and the resulting number of rows +* @param data array of bytes to convert +* @param size size of data +* @param columns number of columns that the resulting matrix should have. +* @return a reference to a matrix of short where for each row there are columns elements +*/ +i8 **array1dTo2d_i8(i8 *data, int size, int columns) +{ + + int i; + i8 **matrix = + (i8 **) kmalloc(((int)(size / columns)) * sizeof(i8 *), GFP_KERNEL); + if (matrix != NULL) { + for (i = 0; i < (int)(size / columns); i++) { + matrix[i] = + (i8 *) kmalloc(columns * sizeof(i8), GFP_KERNEL); + } + + for (i = 0; i < size; i++) { + matrix[i / columns][i % columns] = data[i]; + } + } + + return matrix; +} + +/** +* Print in the kernel log a label followed by a matrix of short row x columns and free its memory +* @param label pointer to the string to print before the actual matrix +* @param matrix reference to the matrix of short which contain the actual data +* @param row number of rows on which the matrix should be print +* @param column number of columns for each row +*/ +void print_frame_short(char *label, short **matrix, int row, int column) +{ + int i, j; + logError(1, "%s %s \n", tag, label); + for (i = 0; i < row; i++) { + logError(1, "%s ", tag); + for (j = 0; j < column; j++) { + printk("%d ", matrix[i][j]); + } + logError(1, "\n"); + kfree(matrix[i]); + } + kfree(matrix); +} + +/** +* Print in the kernel log a label followed by a matrix of u16 row x columns and free its memory +* @param label pointer to the string to print before the actual matrix +* @param matrix reference to the matrix of u16 which contain the actual data +* @param row number of rows on which the matrix should be print +* @param column number of columns for each row +*/ +void print_frame_u16(char *label, u16 **matrix, int row, int column) +{ + int i, j; + logError(1, "%s %s \n", tag, label); + for (i = 0; i < row; i++) { + logError(0, "%s ", tag); + for (j = 0; j < column; j++) { + printk("%d ", matrix[i][j]); + } + logError(0, "\n"); + kfree(matrix[i]); + } + kfree(matrix); +} + +/** +* Print in the kernel log a label followed by a matrix of u8 row x columns and free its memory +* @param label pointer to the string to print before the actual matrix +* @param matrix reference to the matrix of u8 which contain the actual data +* @param row number of rows on which the matrix should be print +* @param column number of columns for each row +*/ +void print_frame_u8(char *label, u8 **matrix, int row, int column) +{ + int i, j; + logError(1, "%s %s \n", tag, label); + for (i = 0; i < row; i++) { + logError(1, "%s ", tag); + for (j = 0; j < column; j++) { + printk("%d ", matrix[i][j]); + } + logError(1, "\n"); + kfree(matrix[i]); + } + kfree(matrix); +} + +/** +* Print in the kernel log a label followed by a matrix of i8 row x columns and free its memory +* @param label pointer to the string to print before the actual matrix +* @param matrix reference to the matrix of u8 which contain the actual data +* @param row number of rows on which the matrix should be print +* @param column number of columns for each row +*/ +void print_frame_i8(char *label, i8 **matrix, int row, int column) +{ + int i, j; + logError(1, "%s %s \n", tag, label); + for (i = 0; i < row; i++) { + logError(1, "%s ", tag); + for (j = 0; j < column; j++) { + printk("%d ", matrix[i][j]); + } + logError(1, "\n"); + kfree(matrix[i]); + } + kfree(matrix); +} + +/** +* Print in the kernel log a label followed by a matrix of u32 row x columns and free its memory +* @param label pointer to the string to print before the actual matrix +* @param matrix reference to the matrix of u32 which contain the actual data +* @param row number of rows on which the matrix should be print +* @param column number of columns for each row +*/ +void print_frame_u32(char *label, u32 **matrix, int row, int column) +{ + int i, j; + logError(1, "%s %s \n", tag, label); + for (i = 0; i < row; i++) { + logError(0, "%s ", tag); + for (j = 0; j < column; j++) { + printk("%d ", matrix[i][j]); + } + logError(0, "\n"); + kfree(matrix[i]); + } + kfree(matrix); +} + +/** +* Print in the kernel log a label followed by a matrix of int row x columns and free its memory +* @param label pointer to the string to print before the actual matrix +* @param matrix reference to the matrix of int which contain the actual data +* @param row number of rows on which the matrix should be print +* @param column number of columns for each row +*/ +void print_frame_int(char *label, int **matrix, int row, int column) +{ + int i, j; + logError(1, "%s %s \n", tag, label); + for (i = 0; i < row; i++) { + logError(0, "%s ", tag); + for (j = 0; j < column; j++) { + printk("%d ", matrix[i][j]); + } + logError(0, "\n"); + kfree(matrix[i]); + } + kfree(matrix); +} + +/** +* Convert an array of bytes to an u64, src has MSB first (big endian). +* @param src array of bytes +* @param dest pointer to the destination u64. +* @param size size of src (can be <= 8) +* @return OK if success or ERROR_OP_NOT_ALLOW if size exceed 8 +*/ +int u8ToU64_be(u8 *src, u64 *dest, int size) +{ + int i = 0; + + if (size > sizeof(u64)) { + return ERROR_OP_NOT_ALLOW; + } else { + *dest = 0; + + for (i = 0; i < size; i++) { + *dest |= (u64) (src[i]) << ((size - 1 - i) * 8); + } + + return OK; + } +} + +/** +* Convert an u64 to an array of bytes, dest has MSB first (big endian). +* @param src value of u64 +* @param dest pointer to the destination array of bytes. +* @param size size of src (can be <= 8) +* @return OK if success or ERROR_OP_NOT_ALLOW if size exceed 8 +*/ +int u64ToU8_be(u64 src, u8 *dest, int size) +{ + int i = 0; + if (size > sizeof(u64)) { + return ERROR_OP_NOT_ALLOW; + } else { + for (i = 0; i < size; i++) { + dest[i] = (u8) ((src >> ((size - 1 - i) * 8)) & 0xFF); + } + } + + return OK; +} + +/*********** NEW API *************/ + +/** + * Convert a value of an id in a bitmask with a 1 in the position of the value of the id + * @param id Value of the ID to convert + * @param mask pointer to the bitmask that will be updated with the value of id + * @param size dimension in bytes of mask + * @return OK if success or ERROR_OP_NOT_ALLOW if size of mask is not enough to contain ID + */ +int fromIDtoMask(u8 id, u8 *mask, int size) +{ + if (((int)((id) / 8)) < size) { + logError(0, "%s %s: ID = %d Index = %d Position = %d !\n", tag, + __func__, id, ((int)((id) / 8)), (id % 8)); + mask[((int)((id) / 8))] |= 0x01 << (id % 8); + return OK; + } else { + logError(1, + "%s %s: Bitmask too small! Impossible contain ID = %d %d>=%d! ERROR %08X\n", + tag, __func__, id, ((int)((id) / 8)), size, + ERROR_OP_NOT_ALLOW); + return ERROR_OP_NOT_ALLOW; + } +} diff --git a/drivers/input/touchscreen/fts_521/fts_lib/ftsTool.h b/drivers/input/touchscreen/fts_521/fts_lib/ftsTool.h new file mode 100644 index 000000000000..86e20fa94f60 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_lib/ftsTool.h @@ -0,0 +1,56 @@ +/* + +************************************************************************** +** STMicroelectronics ** +************************************************************************** +** marco.cali@st.com ** +************************************************************************** +* * +* FTS Utility Functions * +* * +************************************************************************** +************************************************************************** + +*/ + +/*! +* \file ftsTool.h +* \brief Contains all the definitions to support common operations inside the driver +*/ + +#ifndef FTS_TOOL_H +#define FTS_TOOL_H + +char *printHex(char *label, u8 *buff, int count, u8 *result); +char *printHex_data(char *label, u8 *buff, int count); +int u8ToU16(u8 *src, u16 *dst); +int u8ToU16_be(u8 *src, u16 *dst); +int u8ToU16n(u8 *src, int src_length, u16 *dst); +int u16ToU8(u16 src, u8 *dst); +int u16ToU8_be(u16 src, u8 *dst); +int u16ToU8n_be(u16 *src, int src_length, u8 *dst); +int u8ToU32(u8 *src, u32 *dst); +int u32ToU8(u32 src, u8 *dst); +int u32ToU8_be(u32 src, u8 *dst); +int u8ToU64_be(u8 *src, u64 *dest, int size); +int u64ToU8_be(u64 src, u8 *dest, int size); +int attempt_function(int(*code)(void), unsigned long wait_before_retry, + int retry_count); +int senseOn(void); +int senseOff(void); +void print_frame_short(char *label, short **matrix, int row, int column); +short **array1dTo2d_short(short *data, int size, int columns); +void print_frame_u16(char *label, u16 **matrix, int row, int column); +u16 **array1dTo2d_u16(u16 *data, int size, int columns); +u8 **array1dTo2d_u8(u8 *data, int size, int columns); +i8 **array1dTo2d_i8(i8 *data, int size, int columns); +void print_frame_u8(char *label, u8 **matrix, int row, int column); +void print_frame_i8(char *label, i8 **matrix, int row, int column); +void print_frame_u32(char *label, u32 **matrix, int row, int column); +void print_frame_int(char *label, int **matrix, int row, int column); +int cleanUp(int enableTouch); +int flushFIFO(void); + +int fromIDtoMask(u8 id, u8 *mask, int size); + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_limits.h b/drivers/input/touchscreen/fts_521/fts_limits.h new file mode 100644 index 000000000000..46e09629061b --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_limits.h @@ -0,0 +1,2109 @@ +/*! +* \file fts_limits.h +* \brief Contains the size and the byte array of the production test limit file which contains thresholds used to test data +*/ + +#ifndef FTS_LIMITS_H +#define FTS_LIMITS_H +/*This is an auto generated header file*/ +/*--->Remember to change the name of the two variables!<---*/ +const uint32_t myArray2_size = 16725; + +/** + * Array containing the production limit file + */ +const uint8_t myArray2[] = { + 0x2A, 0x53, 0x54, 0x4F, 0x50, 0x5F, 0x4F, 0x4E, 0x5F, 0x46, 0x41, 0x49, + 0x4C, 0x2C, 0x31, 0x2C, + 0x31, 0x0A, 0x31, 0x0A, 0x2A, 0x53, 0x54, 0x4F, 0x50, 0x5F, 0x4F, 0x4E, + 0x5F, 0x45, 0x52, 0x52, + 0x4F, 0x52, 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x31, 0x0A, 0x2A, 0x46, 0x4F, + 0x52, 0x43, 0x45, 0x5F, + 0x46, 0x57, 0x5F, 0x55, 0x50, 0x44, 0x41, 0x54, 0x45, 0x2C, 0x31, 0x2C, + 0x31, 0x0A, 0x30, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x49, 0x58, 0x31, 0x5F, 0x46, 0x4F, 0x52, 0x43, + 0x45, 0x5F, 0x57, 0x2C, + 0x31, 0x2C, 0x31, 0x0A, 0x32, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x49, 0x58, + 0x32, 0x5F, 0x46, 0x4F, + 0x52, 0x43, 0x45, 0x5F, 0x57, 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x31, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, + 0x49, 0x58, 0x31, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x57, 0x2C, + 0x31, 0x2C, 0x31, 0x0A, + 0x32, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x53, 0x45, + 0x4E, 0x53, 0x45, 0x5F, + 0x57, 0x2C, 0x31, 0x2C, 0x31, 0x0A, 0x31, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, + 0x52, 0x41, 0x57, 0x5F, + 0x44, 0x41, 0x54, 0x41, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, + 0x2C, 0x31, 0x2C, 0x32, + 0x0A, 0x31, 0x30, 0x30, 0x30, 0x2C, 0x31, 0x35, 0x30, 0x30, 0x30, 0x0A, + 0x2A, 0x4D, 0x53, 0x5F, + 0x52, 0x41, 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x47, 0x41, 0x50, + 0x2C, 0x31, 0x2C, 0x31, + 0x0A, 0x33, 0x30, 0x30, 0x30, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, + 0x55, 0x43, 0x48, 0x5F, + 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, 0x31, 0x5F, 0x4D, + 0x49, 0x4E, 0x5F, 0x4D, + 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, 0x2C, 0x36, 0x33, 0x0A, + 0x2A, 0x4D, 0x53, 0x5F, + 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x43, 0x58, 0x32, + 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x32, 0x32, 0x2C, 0x32, 0x37, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x2A, + 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x5F, + 0x43, 0x58, 0x32, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, 0x32, + 0x37, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x41, 0x44, 0x4A, + 0x5F, 0x48, 0x4F, 0x52, + 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x32, 0x32, 0x2C, 0x32, + 0x36, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, + 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x56, + 0x45, 0x52, 0x54, 0x49, + 0x43, 0x41, 0x4C, 0x2C, 0x32, 0x31, 0x2C, 0x32, 0x37, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x2A, + 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x5F, + 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x4D, 0x49, 0x4E, + 0x2C, 0x32, 0x32, 0x2C, + 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, + 0x4F, 0x55, 0x43, 0x48, + 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, + 0x4C, 0x5F, 0x43, 0x58, + 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, 0x32, 0x37, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, + 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x41, + 0x44, 0x4A, 0x5F, 0x48, + 0x4F, 0x52, 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x32, 0x32, + 0x2C, 0x32, 0x36, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, + 0x58, 0x5F, 0x41, 0x44, + 0x4A, 0x5F, 0x56, 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, 0x2C, 0x32, + 0x31, 0x2C, 0x32, 0x37, + 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, 0x34, + 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x4B, 0x45, + 0x59, 0x5F, 0x52, 0x41, + 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, + 0x41, 0x58, 0x2C, 0x31, + 0x2C, 0x32, 0x0A, 0x30, 0x2C, 0x38, 0x30, 0x30, 0x30, 0x0A, 0x2A, 0x4D, + 0x53, 0x5F, 0x4B, 0x45, + 0x59, 0x5F, 0x43, 0x58, 0x31, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, + 0x58, 0x2C, 0x31, 0x2C, + 0x32, 0x0A, 0x30, 0x2C, 0x36, 0x34, 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x4B, + 0x45, 0x59, 0x5F, 0x43, + 0x58, 0x32, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x31, 0x2C, 0x33, 0x0A, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x2A, 0x4D, 0x53, 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x43, 0x58, 0x32, + 0x5F, 0x4D, 0x41, 0x58, + 0x2C, 0x31, 0x2C, 0x33, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, 0x36, + 0x34, 0x0A, 0x2A, 0x4D, + 0x53, 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, + 0x43, 0x58, 0x5F, 0x4D, + 0x49, 0x4E, 0x2C, 0x31, 0x2C, 0x33, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x0A, 0x2A, 0x4D, 0x53, + 0x5F, 0x4B, 0x45, 0x59, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, + 0x58, 0x5F, 0x4D, 0x41, + 0x58, 0x2C, 0x31, 0x2C, 0x33, 0x0A, 0x36, 0x34, 0x2C, 0x36, 0x34, 0x2C, + 0x36, 0x34, 0x0A, 0x2A, + 0x53, 0x53, 0x5F, 0x52, 0x41, 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, + 0x46, 0x4F, 0x52, 0x43, + 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, + 0x32, 0x0A, 0x31, 0x30, + 0x30, 0x30, 0x2C, 0x31, 0x35, 0x30, 0x30, 0x30, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x52, 0x41, 0x57, + 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, + 0x47, 0x41, 0x50, 0x2C, + 0x31, 0x2C, 0x31, 0x0A, 0x33, 0x30, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, + 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x31, + 0x5F, 0x46, 0x4F, 0x52, + 0x43, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, + 0x2C, 0x32, 0x0A, 0x30, + 0x2C, 0x36, 0x33, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x46, 0x4F, 0x52, + 0x43, 0x45, 0x5F, 0x4D, + 0x49, 0x4E, 0x2C, 0x32, 0x32, 0x2C, 0x31, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x46, 0x4F, 0x52, + 0x43, 0x45, 0x5F, 0x4D, + 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x49, 0x58, 0x32, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x56, 0x45, 0x52, + 0x54, 0x49, 0x43, 0x41, + 0x4C, 0x2C, 0x32, 0x31, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, + 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, + 0x53, 0x53, 0x5F, 0x54, + 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, + 0x54, 0x4F, 0x54, 0x41, + 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, + 0x49, 0x4E, 0x2C, 0x32, + 0x32, 0x2C, 0x31, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, + 0x30, 0x0A, 0x30, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x46, 0x4F, + 0x52, 0x43, 0x45, 0x5F, + 0x4D, 0x41, 0x58, 0x2C, 0x32, 0x32, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, + 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x41, + 0x44, 0x4A, 0x5F, 0x56, + 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, 0x2C, 0x32, 0x31, 0x2C, 0x31, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, + 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x43, 0x58, 0x31, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, + 0x4D, 0x49, 0x4E, 0x5F, + 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, 0x2C, 0x36, 0x33, + 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x43, 0x58, + 0x32, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, + 0x32, 0x32, 0x2C, 0x31, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, + 0x45, 0x5F, 0x43, 0x58, + 0x32, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, + 0x32, 0x32, 0x2C, 0x31, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, + 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, + 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, + 0x32, 0x5F, 0x41, 0x44, + 0x4A, 0x5F, 0x56, 0x45, 0x52, 0x54, 0x49, 0x43, 0x41, 0x4C, 0x2C, 0x32, + 0x31, 0x2C, 0x31, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, + 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, + 0x58, 0x5F, 0x46, 0x4F, + 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x49, 0x4E, 0x2C, 0x32, 0x32, 0x2C, 0x31, + 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, + 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x30, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, + 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, + 0x54, 0x41, 0x4C, 0x5F, + 0x43, 0x58, 0x5F, 0x46, 0x4F, 0x52, 0x43, 0x45, 0x5F, 0x4D, 0x41, 0x58, + 0x2C, 0x32, 0x32, 0x2C, + 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, + 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, + 0x4F, 0x54, 0x41, 0x4C, + 0x5F, 0x43, 0x58, 0x5F, 0x41, 0x44, 0x4A, 0x5F, 0x56, 0x45, 0x52, 0x54, + 0x49, 0x43, 0x41, 0x4C, + 0x2C, 0x32, 0x31, 0x2C, 0x31, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, + 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x52, 0x41, + 0x57, 0x5F, 0x44, 0x41, 0x54, 0x41, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, + 0x5F, 0x4D, 0x49, 0x4E, + 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x31, 0x30, 0x30, + 0x30, 0x2C, 0x31, 0x35, + 0x30, 0x30, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x52, 0x41, 0x57, 0x5F, + 0x44, 0x41, 0x54, 0x41, + 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x47, 0x41, 0x50, 0x2C, 0x31, + 0x2C, 0x31, 0x0A, 0x33, + 0x30, 0x30, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, + 0x5F, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, 0x31, 0x5F, 0x53, 0x45, 0x4E, 0x53, + 0x45, 0x5F, 0x4D, 0x49, + 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, 0x2C, + 0x36, 0x33, 0x0A, 0x2A, + 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x5F, + 0x49, 0x58, 0x32, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x49, + 0x4E, 0x2C, 0x31, 0x2C, + 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, + 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, + 0x32, 0x5F, 0x53, 0x45, + 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x37, + 0x0A, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, + 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x49, 0x58, + 0x32, 0x5F, 0x41, 0x44, + 0x4A, 0x5F, 0x48, 0x4F, 0x52, 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, + 0x2C, 0x31, 0x2C, 0x32, + 0x36, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, + 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, + 0x4F, 0x54, 0x41, 0x4C, + 0x5F, 0x49, 0x58, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x49, + 0x4E, 0x2C, 0x31, 0x2C, + 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, + 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, 0x53, + 0x5F, 0x54, 0x4F, 0x55, + 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, 0x4F, + 0x54, 0x41, 0x4C, 0x5F, + 0x49, 0x58, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x41, 0x58, + 0x2C, 0x31, 0x2C, 0x32, + 0x37, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, + 0x56, 0x45, 0x5F, 0x54, + 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x49, 0x58, 0x5F, 0x41, 0x44, 0x4A, 0x5F, + 0x48, 0x4F, 0x52, 0x49, + 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x31, 0x2C, 0x32, 0x36, 0x0A, + 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x2C, + 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, + 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, 0x58, 0x31, 0x5F, 0x53, 0x45, 0x4E, + 0x53, 0x45, 0x5F, 0x4D, + 0x49, 0x4E, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, 0x0A, 0x30, + 0x2C, 0x36, 0x33, 0x0A, + 0x2A, 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, + 0x54, 0x49, 0x56, 0x45, + 0x5F, 0x43, 0x58, 0x32, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, + 0x49, 0x4E, 0x2C, 0x31, + 0x2C, 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, + 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, + 0x58, 0x32, 0x5F, 0x53, + 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x41, 0x58, 0x2C, 0x31, 0x2C, 0x32, + 0x37, 0x0A, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, + 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, + 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x43, + 0x58, 0x32, 0x5F, 0x41, + 0x44, 0x4A, 0x5F, 0x48, 0x4F, 0x52, 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, + 0x4C, 0x2C, 0x31, 0x2C, + 0x32, 0x36, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x0A, 0x2A, + 0x53, 0x53, 0x5F, 0x54, + 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, + 0x54, 0x4F, 0x54, 0x41, + 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, + 0x49, 0x4E, 0x2C, 0x31, + 0x2C, 0x32, 0x37, 0x0A, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, + 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x2C, 0x30, 0x0A, 0x2A, 0x53, + 0x53, 0x5F, 0x54, 0x4F, + 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x5F, 0x54, + 0x4F, 0x54, 0x41, 0x4C, + 0x5F, 0x43, 0x58, 0x5F, 0x53, 0x45, 0x4E, 0x53, 0x45, 0x5F, 0x4D, 0x41, + 0x58, 0x2C, 0x31, 0x2C, + 0x32, 0x37, 0x0A, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, + 0x35, 0x35, 0x0A, 0x2A, + 0x53, 0x53, 0x5F, 0x54, 0x4F, 0x55, 0x43, 0x48, 0x5F, 0x41, 0x43, 0x54, + 0x49, 0x56, 0x45, 0x5F, + 0x54, 0x4F, 0x54, 0x41, 0x4C, 0x5F, 0x43, 0x58, 0x5F, 0x41, 0x44, 0x4A, + 0x5F, 0x48, 0x4F, 0x52, + 0x49, 0x5A, 0x4F, 0x4E, 0x54, 0x41, 0x4C, 0x2C, 0x31, 0x2C, 0x32, 0x36, + 0x0A, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, + 0x2C, 0x32, 0x35, 0x35, 0x0A, +}; + +#endif diff --git a/drivers/input/touchscreen/fts_521/fts_proc.c b/drivers/input/touchscreen/fts_521/fts_proc.c new file mode 100644 index 000000000000..a9501b58cba1 --- /dev/null +++ b/drivers/input/touchscreen/fts_521/fts_proc.c @@ -0,0 +1,2451 @@ +/* + + ************************************************************************** + ** STMicroelectronics ** + ************************************************************************** + ** marco.cali@st.com ** + ************************************************************************** + * * + * Utilities published in /proc/fts * + * * + ************************************************************************** + ************************************************************************** + + */ + +/*! +* \file fts_proc.c +* \brief contains the function and variables needed to publish a file node in the file system which allow to communicate with the IC from userspace +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "fts.h" +#include "fts_lib/ftsCompensation.h" +#include "fts_lib/ftsCore.h" +#include "fts_lib/ftsIO.h" +#include "fts_lib/ftsError.h" +#include "fts_lib/ftsFrame.h" +#include "fts_lib/ftsFlash.h" +#include "fts_lib/ftsTest.h" +#include "fts_lib/ftsTime.h" +#include "fts_lib/ftsTool.h" + +#define DRIVER_TEST_FILE_NODE "driver_test" +#define CHUNK_PROC 1024 +#define DIAGNOSTIC_NUM_FRAME 10 + +/** @defgroup proc_file_code Proc File Node +* @ingroup file_nodes +* The /proc/fts/driver_test file node provide expose the most important API implemented into the driver to execute any possible operation into the IC \n +* Thanks to a series of Operation Codes, each of them, with a different set of parameter, it is possible to select a function to execute\n +* The result of the function is usually returned into the shell as an ASCII hex string where each byte is encoded in two chars.\n +* @{ +*/ + +/*Bus operations*/ +#define CMD_READ 0x00 +#define CMD_WRITE 0x01 +#define CMD_WRITEREAD 0x02 +#define CMD_WRITETHENWRITEREAD 0x03 +#define CMD_WRITEU8UX 0x04 +#define CMD_WRITEREADU8UX 0x05 +#define CMD_WRITEU8UXTHENWRITEU8UX 0x06 +#define CMD_WRITEU8UXTHENWRITEREADU8UX 0x07 +#define CMD_GETLIMITSFILE 0x08 +#define CMD_GETFWFILE 0x09 +#define CMD_VERSION 0x0A +#define CMD_READCONFIG 0x0B + +/*GUI utils byte ver*/ +#define CMD_READ_BYTE 0xF0 +#define CMD_WRITE_BYTE 0xF1 +#define CMD_WRITEREAD_BYTE 0xF2 +#define CMD_WRITETHENWRITEREAD_BYTE 0xF3 +#define CMD_WRITEU8UX_BYTE 0xF4 +#define CMD_WRITEREADU8UX_BYTE 0xF5 +#define CMD_WRITEU8UXTHENWRITEU8UX_BYTE 0xF6 +#define CMD_WRITEU8UXTHENWRITEREADU8UX_BYTE 0xF7 +#define CMD_GETLIMITSFILE_BYTE 0xF8 +#define CMD_GETFWFILE_BYTE 0xF9 +#define CMD_VERSION_BYTE 0xFA +#define CMD_CHANGE_OUTPUT_MODE 0xFF + +/*Core/Tools*/ +#define CMD_POLLFOREVENT 0x11 +#define CMD_SYSTEMRESET 0x12 +#define CMD_CLEANUP 0x13 +#define CMD_POWERCYCLE 0x14 +#define CMD_READSYSINFO 0x15 +#define CMD_FWWRITE 0x16 +#define CMD_INTERRUPT 0x17 + +/*Frame*/ +#define CMD_GETFORCELEN 0x20 +#define CMD_GETSENSELEN 0x21 +#define CMD_GETMSFRAME 0x23 +#define CMD_GETSSFRAME 0x24 + +/*Compensation*/ +#define CMD_REQCOMPDATA 0x30 +#define CMD_READCOMPDATAHEAD 0x31 +#define CMD_READMSCOMPDATA 0x32 +#define CMD_READSSCOMPDATA 0x33 +#define CMD_READTOTMSCOMPDATA 0x35 +#define CMD_READTOTSSCOMPDATA 0x36 + +/*FW Update*/ +#define CMD_GETFWVER 0x40 +#define CMD_FLASHUNLOCK 0x42 +#define CMD_READFWFILE 0x43 +#define CMD_FLASHPROCEDURE 0x44 +#define CMD_FLASHERASEUNLOCK 0x45 +#define CMD_FLASHERASEPAGE 0x46 + +/*MP test*/ +#define CMD_ITOTEST 0x50 +#define CMD_INITTEST 0x51 +#define CMD_MSRAWTEST 0x52 +#define CMD_MSINITDATATEST 0x53 +#define CMD_SSRAWTEST 0x54 +#define CMD_SSINITDATATEST 0x55 +#define CMD_MAINTEST 0x56 +#define CMD_FREELIMIT 0x57 + +/*Diagnostic*/ +#define CMD_DIAGNOSTIC 0x60 + + +#define CMD_CHANGE_SAD 0x70 + +static u8 bin_output; +/** @}*/ + +/** @defgroup scriptless Scriptless Protocol + * @ingroup proc_file_code + * Scriptless Protocol allows ST Software (such as FingerTip Studio etc) to communicate with the IC from an user space. + * This mode gives access to common bus operations (write, read etc) and support additional functionalities. \n + * The protocol is based on exchange of binary messages included between a start and an end byte + * @{ + */ + +#define MESSAGE_START_BYTE 0x7B +#define MESSAGE_END_BYTE 0x7D +#define MESSAGE_MIN_HEADER_SIZE 8 + +/** + * Possible actions that can be requested by an host + */ +typedef enum { + ACTION_WRITE = (u16) 0x0001, + ACTION_READ = (u16) 0x0002, + ACTION_WRITE_READ = (u16) 0x0003, + ACTION_GET_VERSION = (u16) 0x0004, + ACTION_WRITEU8UX = (u16) 0x0011, + ACTION_WRITEREADU8UX = (u16) 0x0012, + ACTION_WRITETHENWRITEREAD = (u16) 0x0013, + ACTION_WRITEU8XTHENWRITEREADU8UX = (u16) 0x0014, + ACTION_WRITEU8UXTHENWRITEU8UX = (u16) 0x0015, + ACTION_GET_FW = (u16) 0x1000, + ACTION_GET_LIMIT = (u16) 0x1001 +} Actions; + +/** + * Struct used to contain info of the message received by the host in Scriptless mode + */ +typedef struct { + u16 msg_size; + u16 counter; + Actions action; + u8 dummy; +} Message; + +/** @}*/ + +extern TestToDo tests; +extern SysInfo systemInfo; + +static int limit; +static int chunk; +static int printed; +static struct proc_dir_entry *fts_dir; +static u8 *driver_test_buff; +char buf_chunk[CHUNK_PROC]; +static Message mess; + +/************************ SEQUENTIAL FILE UTILITIES **************************/ +/** +* This function is called at the beginning of the stream to a sequential file or every time into the sequential were already written PAGE_SIZE bytes and the stream need to restart +* @param s pointer to the sequential file on which print the data +* @param pos pointer to the offset where write the data +* @return NULL if there is no data to print or the pointer to the beginning of the data that need to be printed +*/ +static void *fts_seq_start(struct seq_file *s, loff_t *pos) +{ + logError(0, + "%s %s: Entering start(), pos = %Ld limit = %d printed = %d \n", + tag, __func__, *pos, limit, printed); + + if (driver_test_buff == NULL && *pos == 0) { + logError(1, "%s %s: No data to print!\n", tag, __func__); + driver_test_buff = (u8 *) kmalloc(13 * sizeof(u8), GFP_KERNEL); + + snprintf(driver_test_buff, PAGE_SIZE, "{ %08X }\n", ERROR_OP_NOT_ALLOW); + + limit = strlen(driver_test_buff); + } else { + if (*pos != 0) + *pos += chunk - 1; + + if (*pos >= limit) { + return NULL; + } + } + + chunk = CHUNK_PROC; + if (limit - *pos < CHUNK_PROC) + chunk = limit - *pos; + memset(buf_chunk, 0, CHUNK_PROC); + memcpy(buf_chunk, &driver_test_buff[(int)*pos], chunk); + + return buf_chunk; +} + +/** +* This function actually print a chunk amount of data in the sequential file +* @param s pointer to the sequential file where to print the data +* @param v pointer to the data to print +* @return 0 +*/ +static int fts_seq_show(struct seq_file *s, void *v) +{ + seq_write(s, (u8 *) v, chunk); + printed += chunk; + return 0; +} + +/** +* This function update the pointer and the counters to the next data to be printed +* @param s pointer to the sequential file where to print the data +* @param v pointer to the data to print +* @param pos pointer to the offset where write the next data +* @return NULL if there is no data to print or the pointer to the beginning of the next data that need to be printed +*/ +static void *fts_seq_next(struct seq_file *s, void *v, loff_t *pos) +{ + (*pos) += chunk; + chunk = CHUNK_PROC; + + if (*pos >= limit) + return NULL; + else { + if (limit - *pos < CHUNK_PROC) + chunk = limit - *pos; + } + + memset(buf_chunk, 0, CHUNK_PROC); + memcpy(buf_chunk, &driver_test_buff[(int)*pos], chunk); + return buf_chunk; +} + +/** +* This function is called when there are no more data to print the stream need to be terminated or when PAGE_SIZE data were already written into the sequential file +* @param s pointer to the sequential file where to print the data +* @param v pointer returned by fts_seq_next +*/ +static void fts_seq_stop(struct seq_file *s, void *v) +{ + + if (v) { + /*logError(0, "%s %s: v is %X.\n", tag, __func__, v);*/ + } else { + limit = 0; + chunk = 0; + printed = 0; + if (driver_test_buff != NULL) { + kfree(driver_test_buff); + driver_test_buff = NULL; + + } else { + /*logError(0, "%s %s: driver_test_buff is already null.\n", tag, __func__);*/ + } + } + +} + +/** +* Struct where define and specify the functions which implements the flow for writing on a sequential file +*/ +static struct seq_operations fts_seq_ops = { + .start = fts_seq_start, + .next = fts_seq_next, + .stop = fts_seq_stop, + .show = fts_seq_show +}; + +/** +* This function open a sequential file +* @param inode Inode in the file system that was called and triggered this function +* @param file file associated to the file node +* @return error code, 0 if success +*/ +static int fts_open(struct inode *inode, struct file *file) +{ + return seq_open(file, &fts_seq_ops); +}; + +/*****************************************************************************/ + +/**************************** DRIVER TEST ************************************/ + +/** @addtogroup proc_file_code + * @{ + */ + +/** + * Receive the OP code and the inputs from shell when the file node is called, parse it and then execute the corresponding function + * echo cmd+parameters > /proc/fts/driver_test to execute the select command + * cat /proc/fts/driver_test to obtain the result into the shell \n + * the string returned in the shell is made up as follow: \n + * { = start byte \n + * the answer content and format strictly depend on the cmd executed. In general can be: an HEX string or a byte array (e.g in case of 0xF- commands) \n + * } = end byte \n + */ +static ssize_t fts_driver_test_write(struct file *file, const char __user *buf, + size_t count, loff_t *pos) +{ + int numberParam = 0; + struct fts_ts_info *info = dev_get_drvdata(getDev()); + char *p = NULL; + char pbuf[count]; + char path[100] = { 0 }; + int res = -1, j, index = 0; + int size = 6; + int temp, byte_call = 0; + u16 byteToRead = 0; + u32 fileSize = 0; + u8 *readData = NULL; + u8 *cmd = NULL; + u32 funcToTest[((count + 1) / 3)]; + u64 addr = 0; + MutualSenseFrame frameMS; + SelfSenseFrame frameSS; + + DataHeader dataHead; + MutualSenseData compData; + SelfSenseData comData; + TotMutualSenseData totCompData; + TotSelfSenseData totComData; + + u64 address; + u16 fw_version; + u16 config_id; + + Firmware fw; + LimitFile lim; + + mess.dummy = 0; + mess.action = 0; + mess.msg_size = 0; + + cmd = (u8 *)kzalloc(sizeof(u8) * count, GFP_KERNEL); + if (!cmd) { + res = ERROR_ALLOC; + goto END; + } + if (access_ok(VERIFY_READ, buf, count) < OK + || copy_from_user(pbuf, buf, count) != 0) { + res = ERROR_ALLOC; + goto END; + } + + p = pbuf; + if (count > MESSAGE_MIN_HEADER_SIZE - 1 && p[0] == MESSAGE_START_BYTE) { + logError(0, "%s Enter in Byte Mode! \n", tag); + byte_call = 1; + mess.msg_size = (p[1] << 8) | p[2]; + mess.counter = (p[3] << 8) | p[4]; + mess.action = (p[5] << 8) | p[6]; + logError(0, + "%s Message received: size = %d, counter_id = %d, action = %04X \n", + tag, mess.msg_size, mess.counter, mess.action); + size = MESSAGE_MIN_HEADER_SIZE + 2; + if (count < mess.msg_size || p[count - 2] != MESSAGE_END_BYTE) { + logError(1, + "%s number of byte received or end byte wrong! msg_size = %d != %d, last_byte = %02X != %02X ... ERROR %08X\n", + tag, mess.msg_size, count, p[count - 1], + MESSAGE_END_BYTE, ERROR_OP_NOT_ALLOW); + res = ERROR_OP_NOT_ALLOW; + goto END; + + } else { + numberParam = mess.msg_size - MESSAGE_MIN_HEADER_SIZE + 1; + size = MESSAGE_MIN_HEADER_SIZE + 2; + switch (mess.action) { + case ACTION_READ: + cmd[0] = funcToTest[0] = CMD_READ_BYTE; + break; + + case ACTION_WRITE: + cmd[0] = funcToTest[0] = CMD_WRITE_BYTE; + break; + + case ACTION_WRITE_READ: + cmd[0] = funcToTest[0] = CMD_WRITEREAD_BYTE; + break; + + case ACTION_GET_VERSION: + cmd[0] = funcToTest[0] = CMD_VERSION_BYTE; + break; + + case ACTION_WRITETHENWRITEREAD: + cmd[0] = funcToTest[0] = + CMD_WRITETHENWRITEREAD_BYTE; + break; + + case ACTION_WRITEU8UX: + cmd[0] = funcToTest[0] = CMD_WRITEU8UX_BYTE; + break; + + case ACTION_WRITEREADU8UX: + cmd[0] = funcToTest[0] = CMD_WRITEREADU8UX_BYTE; + break; + + case ACTION_WRITEU8UXTHENWRITEU8UX: + cmd[0] = funcToTest[0] = + CMD_WRITEU8UXTHENWRITEU8UX_BYTE; + break; + + case ACTION_WRITEU8XTHENWRITEREADU8UX: + cmd[0] = funcToTest[0] = + CMD_WRITEU8UXTHENWRITEREADU8UX_BYTE; + break; + + case ACTION_GET_FW: + cmd[0] = funcToTest[0] = CMD_GETFWFILE_BYTE; + break; + + case ACTION_GET_LIMIT: + cmd[0] = funcToTest[0] = CMD_GETLIMITSFILE_BYTE; + break; + + default: + logError(1, + "%s Invalid Action = %d ... ERROR %08X\n", + tag, mess.action, ERROR_OP_NOT_ALLOW); + res = ERROR_OP_NOT_ALLOW; + goto END; + } + + if (numberParam - 1 != 0) + memcpy(&cmd[1], &p[7], numberParam - 1); + } + } else { + if (((count + 1) / 3) >= 1) { + sscanf(p, "%02X ", &funcToTest[0]); + p += 3; + cmd[0] = (u8) funcToTest[0]; + numberParam = 1; + } else { + res = ERROR_OP_NOT_ALLOW; + goto END; + } + + logError(1, "%s functionToTest[0] = %02X cmd[0]= %02X\n", tag, + funcToTest[0], cmd[0]); + switch (funcToTest[0]) { + case CMD_GETFWFILE: + case CMD_GETLIMITSFILE: + if (count - 2 - 1 > 1) { + numberParam = 2; + sscanf(p, "%100s", path); + } + break; + + default: + for (; numberParam < (count + 1) / 3; numberParam++) { + sscanf(p, "%02X ", &funcToTest[numberParam]); + p += 3; + cmd[numberParam] = (u8) funcToTest[numberParam]; + logError(1, + "%s functionToTest[%d] = %02X cmd[%d]= %02X\n", + tag, numberParam, + funcToTest[numberParam], numberParam, + cmd[numberParam]); + } + } + + } + + fw.data = NULL; + lim.data = NULL; + + logError(1, "%s Number of Parameters = %d \n", tag, numberParam); + + if (numberParam >= 1) { + switch (funcToTest[0]) { + case CMD_VERSION_BYTE: + logError(0, "%s %s: Get Version Byte \n", tag, __func__, + res); + byteToRead = 2; + mess.dummy = 0; + readData = + (u8 *) kmalloc(byteToRead * sizeof(u8), GFP_KERNEL); + size += byteToRead; + if (readData != NULL) { + readData[0] = (u8) (FTS_TS_DRV_VER >> 24); + readData[1] = (u8) (FTS_TS_DRV_VER >> 16); + res = OK; + logError(0, "%s %s: Version = %02X%02X \n", tag, + __func__, readData[0], readData[1]); + } else { + res = ERROR_ALLOC; + logError(1, + "%s %s: Impossible allocate memory... ERROR %08X \n", + tag, __func__, res); + } + break; + + case CMD_VERSION: + byteToRead = 2 * sizeof(u32); + mess.dummy = 0; + readData = + (u8 *) kmalloc(byteToRead * sizeof(u8), GFP_KERNEL); + u32ToU8_be(FTS_TS_DRV_VER, readData); + fileSize = 0; +#ifdef FW_H_FILE + fileSize |= 0x00010000; +#endif + +#ifdef LIMITS_H_FILE + fileSize |= 0x00020000; +#endif + +#ifdef USE_ONE_FILE_NODE + fileSize |= 0x00040000; +#endif + +#ifdef FW_UPDATE_ON_PROBE + fileSize |= 0x00080000; +#endif + +#ifdef PRE_SAVED_METHOD + fileSize |= 0x00100000; +#endif + +#ifdef USE_GESTURE_MASK + fileSize |= 0x00100000; +#endif + +#ifdef I2C_INTERFACE + fileSize |= 0x00200000; +#endif + +#ifdef PHONE_KEY + fileSize |= 0x00000100; +#endif + +#ifdef GESTURE_MODE + fromIDtoMask(FEAT_SEL_GESTURE, (u8 *)&fileSize, 4); +#endif + +#ifdef GRIP_MODE + fromIDtoMask(FEAT_SEL_GRIP, (u8 *)&fileSize, 4); +#endif + +#ifdef CHARGER_MODE + fromIDtoMask(FEAT_SEL_CHARGER, (u8 *)&fileSize, 4); +#endif + +#ifdef GLOVE_MODE + fromIDtoMask(FEAT_SEL_GLOVE, (u8 *)&fileSize, 4); +#endif + +#ifdef COVER_MODE + fromIDtoMask(FEAT_SEL_COVER, (u8 *)&fileSize, 4); +#endif + +#ifdef STYLUS_MODE + fromIDtoMask(FEAT_SEL_STYLUS, (u8 *)&fileSize, 4); +#endif + + u32ToU8_be(fileSize, &readData[4]); + res = OK; + size += (byteToRead * sizeof(u8)); + break; + + case CMD_WRITEREAD: + case CMD_WRITEREAD_BYTE: + if (numberParam >= 5) { + temp = numberParam - 4; + if (cmd[numberParam - 1] == 0) { + mess.dummy = 0; + } else + mess.dummy = 1; + + u8ToU16_be(&cmd[numberParam - 3], &byteToRead); + logError(0, "%s bytesToRead = %d \n", tag, + byteToRead + mess.dummy); + + readData = + (u8 *) kmalloc((byteToRead + mess.dummy) * + sizeof(u8), GFP_KERNEL); + res = + fts_writeRead_dma_safe(&cmd[1], temp, readData, + byteToRead + mess.dummy); + size += (byteToRead * sizeof(u8)); + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_WRITE: + case CMD_WRITE_BYTE: + if (numberParam >= 2) { + temp = numberParam - 1; + res = fts_write_dma_safe(&cmd[1], temp); + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_READ: + case CMD_READ_BYTE: + if (numberParam >= 3) { + if (numberParam == 3 + || (numberParam == 4 + && cmd[numberParam - 1] == 0)) { + mess.dummy = 0; + } else + mess.dummy = 1; + u8ToU16_be(&cmd[1], &byteToRead); + readData = + (u8 *) kmalloc((byteToRead + mess.dummy) * + sizeof(u8), GFP_KERNEL); + res = + fts_read_dma_safe(readData, byteToRead + mess.dummy); + size += (byteToRead * sizeof(u8)); + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_WRITETHENWRITEREAD: + case CMD_WRITETHENWRITEREAD_BYTE: + if (numberParam >= 6) { + u8ToU16_be(&cmd[numberParam - 2], &byteToRead); + readData = + (u8 *) kmalloc(byteToRead * sizeof(u8), + GFP_KERNEL); + res = + fts_writeThenWriteRead(&cmd[3], cmd[1], + &cmd[3 + + (int)cmd[1]], + cmd[2], readData, + byteToRead); + size += (byteToRead * sizeof(u8)); + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_WRITEU8UX: + case CMD_WRITEU8UX_BYTE: + if (numberParam >= 4) { + if (cmd[2] <= sizeof(u64)) { + u8ToU64_be(&cmd[3], &addr, cmd[2]); + logError(0, "%s addr = %016X %ld \n", + tag, addr, addr); + res = + fts_writeU8UX(cmd[1], cmd[2], addr, + &cmd[3 + cmd[2]], + (numberParam - + cmd[2] - 3)); + } else { + logError(1, "%s Wrong address size!\n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_WRITEREADU8UX: + case CMD_WRITEREADU8UX_BYTE: + if (numberParam >= 6) { + + if (cmd[2] <= sizeof(u64)) { + + u8ToU64_be(&cmd[3], &addr, cmd[2]); + u8ToU16_be(&cmd[numberParam - 3], + &byteToRead); + readData = + (u8 *) kmalloc(byteToRead * + sizeof(u8), + GFP_KERNEL); + logError(0, + "%s addr = %016X byteToRead = %d \n", + tag, addr, byteToRead); + res = + fts_writeReadU8UX(cmd[1], cmd[2], + addr, readData, + byteToRead, + cmd[numberParam - + 1]); + size += (byteToRead * sizeof(u8)); + + } else { + logError(1, "%s Wrong address size!\n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_WRITEU8UXTHENWRITEU8UX: + case CMD_WRITEU8UXTHENWRITEU8UX_BYTE: + if (numberParam >= 6) { + if ((cmd[2] + cmd[4]) <= sizeof(u64)) { + u8ToU64_be(&cmd[5], &addr, + cmd[2] + cmd[4]); + logError(0, "%s addr = %016X %ld \n", + tag, addr, addr); + res = + fts_writeU8UXthenWriteU8UX(cmd[1], + cmd[2], + cmd[3], + cmd[4], + addr, + &cmd[5 + + cmd + [2] + + + cmd + [4]], + (numberParam + - + cmd[2] - + cmd[4] - + 5)); + } else { + logError(1, "%s Wrong address size! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_WRITEU8UXTHENWRITEREADU8UX: + case CMD_WRITEU8UXTHENWRITEREADU8UX_BYTE: + if (numberParam >= 8) { + if ((cmd[2] + cmd[4]) <= sizeof(u64)) { + u8ToU64_be(&cmd[5], &addr, + cmd[2] + cmd[4]); + logError(1, + "%s %s: cmd[5] = %02X, addr = %016X \n", + tag, __func__, cmd[5], addr); + u8ToU16_be(&cmd[numberParam - 3], + &byteToRead); + readData = + (u8 *) kmalloc(byteToRead * + sizeof(u8), + GFP_KERNEL); + res = + fts_writeU8UXthenWriteReadU8UX(cmd + [1], + cmd + [2], + cmd + [3], + cmd + [4], + addr, + readData, + byteToRead, + cmd + [numberParam + - + 1]); + size += (byteToRead * sizeof(u8)); + } else { + logError(1, + "%s Wrong total address size! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + break; + + case CMD_CHANGE_OUTPUT_MODE: + if (numberParam >= 2) { + bin_output = cmd[1]; + logError(0, + "%s Setting Scriptless output mode: %d \n", + tag, bin_output); + res = OK; + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_FWWRITE: + if (numberParam >= 3) { + if (numberParam >= 2) { + temp = numberParam - 1; + res = fts_writeFwCmd(&cmd[1], temp); + } else { + logError(1, "%s Wrong parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_INTERRUPT: + if (numberParam >= 2) { + if (cmd[1] == 1) + res = fts_enableInterrupt(); + else + res = fts_disableInterrupt(); + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_READCONFIG: + if (numberParam == 5) { + byteToRead = + ((funcToTest[3] << 8) | funcToTest[4]); + readData = + (u8 *) kmalloc(byteToRead * sizeof(u8), + GFP_KERNEL); + res = + readConfig((u16) + ((((u8) funcToTest[1] & 0x00FF) + << 8) + + ((u8) funcToTest[2] & 0x00FF)), + readData, byteToRead); + size += (byteToRead * sizeof(u8)); + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_POLLFOREVENT: + if (numberParam >= 5) { + temp = (int)funcToTest[1]; + if (numberParam == 5 + (temp - 1) && temp != 0) { + readData = + (u8 *) kmalloc(FIFO_EVENT_SIZE * + sizeof(u8), + GFP_KERNEL); + res = + pollForEvent((int *)&funcToTest[2], + temp, readData, + ((funcToTest[temp + 2] + & 0x00FF) << 8) + + (funcToTest[temp + 3] & + 0x00FF)); + if (res >= OK) + res = OK; + size += (FIFO_EVENT_SIZE * sizeof(u8)); + byteToRead = FIFO_EVENT_SIZE; + } else { + logError(1, "%s Wrong parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_SYSTEMRESET: + res = fts_system_reset(); + + break; + + case CMD_READSYSINFO: + if (numberParam == 2) { + res = readSysInfo(funcToTest[1]); + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + break; + + case CMD_CLEANUP: + if (numberParam == 2) { + res = cleanUp(funcToTest[1]); + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + + break; + + case CMD_GETFORCELEN: + temp = getForceLen(); + if (temp < OK) + res = temp; + else { + size += (1 * sizeof(u8)); + res = OK; + } + break; + + case CMD_GETSENSELEN: + temp = getSenseLen(); + if (temp < OK) + res = temp; + else { + size += (1 * sizeof(u8)); + res = OK; + } + break; + + case CMD_GETMSFRAME: + if (numberParam == 2) { + logError(0, "%s Get 1 MS Frame \n", tag); + setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + flushFIFO(); + res = + getMSFrame3((MSFrameType) cmd[1], &frameMS); + if (res < 0) { + logError(0, + "%s Error while taking the MS frame... ERROR %08X \n", + tag, res); + + } else { + logError(0, + "%s The frame size is %d words\n", + tag, res); + size += (res * sizeof(short) + 2); + /* set res to OK because if getMSFrame is + successful res = number of words read + */ + res = OK; + print_frame_short("MS frame =", + array1dTo2d_short + (frameMS.node_data, + frameMS. + node_data_size, + frameMS.header. + sense_node), + frameMS.header. + force_node, + frameMS.header. + sense_node); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + /*read self raw */ + case CMD_GETSSFRAME: + if (numberParam == 2) { + logError(0, "%s Get 1 SS Frame \n", tag); + flushFIFO(); + setScanMode(SCAN_MODE_ACTIVE, 0x01); + mdelay(WAIT_FOR_FRESH_FRAMES); + setScanMode(SCAN_MODE_ACTIVE, 0x00); + mdelay(WAIT_AFTER_SENSEOFF); + res = + getSSFrame3((SSFrameType) cmd[1], &frameSS); + + if (res < OK) { + logError(0, + "%s Error while taking the SS frame... ERROR %08X \n", + tag, res); + + } else { + logError(0, + "%s The frame size is %d words\n", + tag, res); + size += (res * sizeof(short) + 2); + /* set res to OK because if getMSFrame is + successful res = number of words read + */ + res = OK; + print_frame_short("SS force frame =", + array1dTo2d_short + (frameSS.force_data, + frameSS.header. + force_node, 1), + frameSS.header. + force_node, 1); + print_frame_short("SS sense frame =", + array1dTo2d_short + (frameSS.sense_data, + frameSS.header. + sense_node, + frameSS.header. + sense_node), 1, + frameSS.header. + sense_node); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_REQCOMPDATA: + if (numberParam == 2) { + logError(0, + "%s Requesting Compensation Data \n", + tag); + res = requestCompensationData(cmd[1]); + + if (res < OK) { + logError(0, + "%s Error requesting compensation data ERROR %08X \n", + tag, res); + } else { + logError(0, + "%s Requesting Compensation Data Finished! \n", + tag); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_READCOMPDATAHEAD: + if (numberParam == 2) { + logError(0, + "%s Requesting Compensation Data \n", + tag); + res = requestCompensationData(cmd[1]); + if (res < OK) { + logError(0, + "%s Error requesting compensation data ERROR %08X \n", + tag, res); + } else { + logError(0, + "%s Requesting Compensation Data Finished! \n", + tag); + res = + readCompensationDataHeader((u8) + funcToTest + [1], + &dataHead, + &address); + if (res < OK) { + logError(0, + "%s Read Compensation Data Header ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s Read Compensation Data Header OK!\n", + tag); + size += (1 * sizeof(u8)); + } + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_READMSCOMPDATA: + if (numberParam == 2) { + logError(0, "%s Get MS Compensation Data \n", + tag); + res = + readMutualSenseCompensationData(cmd[1], + &compData); + + if (res < OK) { + logError(0, + "%s Error reading MS compensation data ERROR %08X \n", + tag, res); + } else { + logError(0, + "%s MS Compensation Data Reading Finished! \n", + tag); + size = + ((compData.node_data_size + + 10) * sizeof(i8)); + print_frame_i8("MS Data (Cx2) =", + array1dTo2d_i8(compData. + node_data, + compData. + node_data_size, + compData. + header. + sense_node), + compData.header. + force_node, + compData.header. + sense_node); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_READSSCOMPDATA: + if (numberParam == 2) { + logError(0, "%s Get SS Compensation Data... \n", + tag); + res = + readSelfSenseCompensationData(cmd[1], + &comData); + if (res < OK) { + logError(0, + "%s Error reading SS compensation data ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s SS Compensation Data Reading Finished! \n", + tag); + size = + ((comData.header.force_node + + comData.header.sense_node) * 2 + + 13) * sizeof(i8); + print_frame_i8("SS Data Ix2_fm = ", + array1dTo2d_i8(comData. + ix2_fm, + comData. + header. + force_node, + comData. + header. + force_node), + 1, + comData.header. + force_node); + print_frame_i8("SS Data Cx2_fm = ", + array1dTo2d_i8(comData. + cx2_fm, + comData. + header. + force_node, + comData. + header. + force_node), + 1, + comData.header. + force_node); + print_frame_i8("SS Data Ix2_sn = ", + array1dTo2d_i8(comData. + ix2_sn, + comData. + header. + sense_node, + comData. + header. + sense_node), + 1, + comData.header. + sense_node); + print_frame_i8("SS Data Cx2_sn = ", + array1dTo2d_i8(comData. + cx2_sn, + comData. + header. + sense_node, + comData. + header. + sense_node), + 1, + comData.header. + sense_node); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_READTOTMSCOMPDATA: + if (numberParam == 2) { + logError(0, + "%s Get TOT MS Compensation Data \n", + tag); + res = + readTotMutualSenseCompensationData(cmd[1], + &totCompData); + + if (res < OK) { + logError(0, + "%s Error reading TOT MS compensation data ERROR %08X \n", + tag, res); + } else { + logError(0, + "%s TOT MS Compensation Data Reading Finished! \n", + tag); + size = + (totCompData.node_data_size * + sizeof(short) + 9); + print_frame_short("MS Data (TOT Cx) =", + array1dTo2d_short + (totCompData. + node_data, + totCompData. + node_data_size, + totCompData.header. + sense_node), + totCompData.header. + force_node, + totCompData.header. + sense_node); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_READTOTSSCOMPDATA: + if (numberParam == 2) { + logError(0, + "%s Get TOT SS Compensation Data... \n", + tag); + res = + readTotSelfSenseCompensationData(cmd[1], + &totComData); + if (res < OK) { + logError(0, + "%s Error reading TOT SS compensation data ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s TOT SS Compensation Data Reading Finished! \n", + tag); + size = + ((totComData.header.force_node + + totComData.header.sense_node) * + 2 * sizeof(short) + 9); + print_frame_u16("SS Data TOT Ix_fm = ", + array1dTo2d_u16 + (totComData.ix_fm, + totComData.header. + force_node, + totComData.header. + force_node), 1, + totComData.header. + force_node); + print_frame_short + ("SS Data TOT Cx_fm = ", + array1dTo2d_short(totComData.cx_fm, + totComData. + header. + force_node, + totComData. + header. + force_node), 1, + totComData.header.force_node); + print_frame_u16("SS Data TOT Ix_sn = ", + array1dTo2d_u16 + (totComData.ix_sn, + totComData.header. + sense_node, + totComData.header. + sense_node), 1, + totComData.header. + sense_node); + print_frame_short + ("SS Data TOT Cx_sn = ", + array1dTo2d_short(totComData.cx_sn, + totComData. + header. + sense_node, + totComData. + header. + sense_node), 1, + totComData.header.sense_node); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_GETFWVER: + res = getFirmwareVersion(&fw_version, &config_id); + if (res < OK) { + logError(1, + "%s Error reading firmware version and config id ERROR %02X\n", + tag, res); + } else { + logError(0, + "%s getFirmwareVersion Finished! \n", + tag); + size += (4) * sizeof(u8); + } + break; + + case CMD_FLASHUNLOCK: + res = flash_unlock(); + if (res < OK) { + logError(1, + "%s Impossible Unlock Flash ERROR %08X\n", + tag, res); + } else { + logError(0, "%s Flash Unlock OK!\n", tag); + } + break; + + case CMD_READFWFILE: + if (numberParam == 2) { + logError(0, "%s Reading FW File... \n", tag); + res = + readFwFile(PATH_FILE_FW, &fw, + funcToTest[1]); + if (res < OK) { + logError(0, + "%s Error reading FW File ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s Read FW File Finished! \n", + tag); + } + kfree(fw.data); + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_FLASHPROCEDURE: + if (numberParam == 3) { + logError(0, + "%s Starting Flashing Procedure... \n", + tag); + res = + flashProcedure(PATH_FILE_FW, cmd[1], + cmd[2]); + if (res < OK) { + logError(0, + "%s Error during flash procedure ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s Flash Procedure Finished! \n", + tag); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_FLASHERASEUNLOCK: + res = flash_erase_unlock(); + if (res < OK) { + logError(0, + "%s Error during flash erase unlock... ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s Flash Erase Unlock Finished! \n", + tag); + } + break; + + case CMD_FLASHERASEPAGE: + if (numberParam == 2) { + logError(0, + "%s Starting Flashing Page Erase... \n", + tag); + res = flash_erase_page_by_page(cmd[1]); + if (res < OK) { + logError(0, + "%s Error during flash page erase... ERROR %08X\n", + tag, res); + } else { + logError(0, + "%s Flash Page Erase Finished! \n", + tag); + } + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + /*ITO TEST */ + case CMD_ITOTEST: + res = production_test_ito(LIMITS_FILE, &tests); + break; + + /*Initialization */ + case CMD_INITTEST: + if (numberParam == 2) { + res = production_test_initialization(cmd[1]); + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_MSRAWTEST: + if (numberParam == 2) + res = + production_test_ms_raw(LIMITS_FILE, cmd[1], + &tests); + else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_MSINITDATATEST: + if (numberParam == 2) + res = + production_test_ms_cx(LIMITS_FILE, cmd[1], + &tests); + else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_SSRAWTEST: + if (numberParam == 2) + res = + production_test_ss_raw(LIMITS_FILE, cmd[1], + &tests); + else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_SSINITDATATEST: + if (numberParam == 2) + res = + production_test_ss_ix_cx(LIMITS_FILE, + cmd[1], &tests); + else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + /*PRODUCTION TEST */ + case CMD_MAINTEST: + if (numberParam == 3) + res = + production_test_main(LIMITS_FILE, cmd[1], + cmd[2], &tests); + else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_FREELIMIT: + res = freeCurrentLimitsFile(); + break; + + case CMD_POWERCYCLE: + res = fts_chip_powercycle(info); + break; + + case CMD_GETLIMITSFILE: + if (numberParam >= 1) { + lim.data = NULL; + lim.size = 0; + if (numberParam == 1) + res = getLimitsFile(LIMITS_FILE, &lim); + else + res = getLimitsFile(path, &lim); + readData = lim.data; + fileSize = lim.size; + size += (fileSize * sizeof(u8)); + if (byte_call == 1) + size += sizeof(u32); + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_GETLIMITSFILE_BYTE: + if (numberParam >= 3) { + lim.data = NULL; + lim.size = 0; + + u8ToU16_be(&cmd[1], &byteToRead); + addr = ((u64) byteToRead) * 4; + + res = getLimitsFile(LIMITS_FILE, &lim); + + readData = lim.data; + fileSize = lim.size; + + if (fileSize > addr) { + logError(1, + "%s Limits dimension expected by Host is less than actual size: expected = %d, real = %d \n", + tag, byteToRead, fileSize); + res = ERROR_OP_NOT_ALLOW; + } + + size += (addr * sizeof(u8)); + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_GETFWFILE: + if (numberParam >= 1) { + + if (numberParam == 1) + res = + getFWdata(PATH_FILE_FW, &readData, + &fileSize); + else + res = + getFWdata(path, &readData, + &fileSize); + + size += (fileSize * sizeof(u8)); + if (byte_call == 1) + size += sizeof(u32); + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; + + case CMD_GETFWFILE_BYTE: + if (numberParam == 3) { + + u8ToU16_be(&cmd[1], &byteToRead); + addr = ((u64) byteToRead) * 4; + + res = + getFWdata(PATH_FILE_FW, &readData, + &fileSize); + if (fileSize > addr) { + logError(1, + "%s FW dimension expected by Host is less than actual size: expected = %d, real = %d \n", + tag, byteToRead, fileSize); + res = ERROR_OP_NOT_ALLOW; + } + + size += (addr * sizeof(u8)); + + } else { + logError(1, "%s Wrong number of parameters! \n", + tag); + res = ERROR_OP_NOT_ALLOW; + } + break; +/* +* finish all the diagnostic command with a goto ERROR in order to skip the modification on driver_test_buff +* remember to set properly the limit and printed variables in order to make the seq_file logic to work +*/ + case CMD_DIAGNOSTIC: + index = 0; + size = 0; + fileSize = 256 * 1024 * sizeof(char); + driver_test_buff = (u8 *) kzalloc(fileSize, GFP_KERNEL); + readData = + (u8 *) + kmalloc((ERROR_DUMP_ROW_SIZE * + ERROR_DUMP_COL_SIZE) * sizeof(u8), + GFP_KERNEL); + if (driver_test_buff == NULL || readData == NULL) { + res = ERROR_ALLOC; + logError(1, + "%s Impossible allocate memory for buffers! ERROR %08X! \n", + tag, res); + goto END; + } + j = snprintf(&driver_test_buff[index], fileSize - index, + "DIAGNOSTIC TEST:\n1) I2C Test: "); + index += j; + + res = + fts_writeReadU8UX(FTS_CMD_HW_REG_R, + ADDR_SIZE_HW_REG, ADDR_DCHIP_ID, + (u8 *)&temp, 2, DUMMY_HW_REG); + if (res < OK) { + logError(1, + "%s Error during I2C test: ERROR %08X! \n", + tag, res); + j = snprintf(&driver_test_buff[index], + fileSize - index, "ERROR %08X \n", + res); + index += j; + res = ERROR_OP_NOT_ALLOW; + goto END_DIAGNOSTIC; + } + + temp &= 0xFFFF; + logError(1, "%s Chip ID = %04X! \n", tag, temp); + j = snprintf(&driver_test_buff[index], fileSize - index, + "DATA = %04X, expected = %02X%02X \n", + temp, DCHIP_ID_1, DCHIP_ID_0); + index += j; + if (temp != ((DCHIP_ID_1 << 8) | DCHIP_ID_0)) { + logError(1, + "%s Wrong CHIP ID, Diagnostic failed! \n", + tag, res); + res = ERROR_OP_NOT_ALLOW; + goto END_DIAGNOSTIC; + } + + j = snprintf(&driver_test_buff[index], fileSize - index, + "Present Driver Mode: %08X \n", + info->mode); + index += j; + + j = snprintf(&driver_test_buff[index], fileSize - index, + "2) FW running: Sensing On..."); + index += j; + logError(1, "%s Sensing On! \n", tag, temp); + readData[0] = FTS_CMD_SCAN_MODE; + readData[1] = SCAN_MODE_ACTIVE; + readData[2] = 0x1; + fts_write(readData, 3); + res = checkEcho(readData, 3); + if (res < OK) { + logError(1, + "%s No Echo received.. ERROR %08X !\n", + tag, res); + j = snprintf(&driver_test_buff[index], + fileSize - index, + "No echo found... ERROR %08X!\n", + res); + index += j; + goto END_DIAGNOSTIC; + } else { + logError(1, "%s Echo FOUND... OK!\n", tag, res); + j = snprintf(&driver_test_buff[index], + fileSize - index, + "Echo FOUND... OK!\n"); + index += j; + } + + logError(1, "%s Reading Frames...! \n", tag, temp); + j = snprintf(&driver_test_buff[index], fileSize - index, + "3) Read Frames: \n"); + index += j; + for (temp = 0; temp < DIAGNOSTIC_NUM_FRAME; temp++) { + logError(1, "%s Iteration n. %d...\n", tag, + temp + 1); + j = snprintf(&driver_test_buff[index], + fileSize - index, + "Iteration n. %d...\n", temp + 1); + index += j; + for (addr = 0; addr < 3; addr++) { + switch (addr) { + case 0: + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "MS RAW FRAME ="); + index += j; + res |= + getMSFrame3(MS_RAW, + &frameMS); + break; + case 2: + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "MS STRENGTH FRAME ="); + index += j; + res |= + getMSFrame3(MS_STRENGTH, + &frameMS); + break; + case 1: + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "MS BASELINE FRAME ="); + index += j; + res |= + getMSFrame3(MS_BASELINE, + &frameMS); + break; + } + if (res < OK) { + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "No data! ERROR %08X \n", + res); + index += j; + } else { + for (address = 0; + address < + frameMS.node_data_size; + address++) { + if (address % + frameMS.header. + sense_node == 0) { + j = snprintf + (&driver_test_buff + [index], + fileSize - + index, + "\n"); + index += j; + } + j = snprintf + (&driver_test_buff + [index], + fileSize - index, + "%5d, ", + frameMS. + node_data + [address]); + index += j; + } + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "\n"); + index += j; + } + if (frameMS.node_data != NULL) + kfree(frameMS.node_data); + } + for (addr = 0; addr < 3; addr++) { + switch (addr) { + case 0: + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "SS RAW FRAME = \n"); + index += j; + res |= + getSSFrame3(SS_RAW, + &frameSS); + break; + case 2: + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "SS STRENGTH FRAME = \n"); + index += j; + res |= + getSSFrame3(SS_STRENGTH, + &frameSS); + break; + case 1: + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "SS BASELINE FRAME = \n"); + index += j; + res |= + getSSFrame3(SS_BASELINE, + &frameSS); + break; + } + if (res < OK) { + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "No data! ERROR %08X \n", + res); + index += j; + } else { + for (address = 0; + address < + frameSS.header.force_node; + address++) { + j = snprintf + (&driver_test_buff + [index], + fileSize - index, + "%d\n", + frameSS. + force_data + [address]); + + index += j; + } + for (address = 0; + address < + frameSS.header.sense_node; + address++) { + j = snprintf + (&driver_test_buff + [index], + fileSize - index, + "%d, ", + frameSS. + sense_data + [address]); + + index += j; + } + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "\n"); + index += j; + } + if (frameSS.force_data != NULL) + kfree(frameSS.force_data); + if (frameSS.sense_data != NULL) + kfree(frameSS.sense_data); + } + } + + logError(1, "%s Reading error info... \n", tag, temp); + j = snprintf(&driver_test_buff[index], fileSize - index, + "4) FW INFO DUMP: "); + index += j; + temp = dumpErrorInfo(readData, ERROR_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE); + if (temp < OK) { + logError(1, + "%s Error during dump: ERROR %08X! \n", + tag, res); + j = snprintf(&driver_test_buff[index], + fileSize - index, "ERROR %08X \n", + temp); + index += j; + } else { + logError(1, "%s DUMP OK! \n", tag, res); + for (temp = 0; + temp < + ERROR_DUMP_ROW_SIZE * ERROR_DUMP_COL_SIZE; + temp++) { + if (temp % ERROR_DUMP_COL_SIZE == 0) { + j = snprintf(&driver_test_buff + [index], + fileSize - index, + "\n%2d - ", + temp / + ERROR_DUMP_COL_SIZE); + index += j; + } + j = snprintf(&driver_test_buff[index], + fileSize - index, "%02X ", + readData[temp]); + index += j; + } + } + res |= temp; + +END_DIAGNOSTIC: + if (res < OK) { + j = snprintf(&driver_test_buff[index], + fileSize - index, + "\nRESULT = FAIL \n"); + index += j; + } else { + j = snprintf(&driver_test_buff[index], + fileSize - index, + "\nRESULT = FINISHED \n"); + index += j; + } + limit = index; + printed = 0; + goto ERROR; + break; + case CMD_CHANGE_SAD: + res = changeSAD(cmd[1]); + break; + + default: + logError(1, "%s COMMAND ID NOT VALID!!! \n", tag); + res = ERROR_OP_NOT_ALLOW; + break; + } + + } else { + logError(1, + "%s NO COMMAND SPECIFIED!!! do: 'echo [cmd_code] [args] > stm_fts_cmd' before looking for result!\n", + tag); + res = ERROR_OP_NOT_ALLOW; + + } + +END: + if (driver_test_buff != NULL) { + logError(1, + "%s Consecutive echo on the file node, free the buffer with the previous result\n", + tag); + kfree(driver_test_buff); + } + + if (byte_call == 0) { + size *= 2; + size += 2; + } else { + if (bin_output != 1) { + size *= 2; + size -= 1; + } else + size += 1; + } + + logError(0, "%s Size = %d\n", tag, size); + driver_test_buff = (u8 *) kzalloc(size, GFP_KERNEL); + logError(0, "%s Finish to allocate memory! \n", tag); + if (driver_test_buff == NULL) { + logError(0, + "%s Unable to allocate driver_test_buff! ERROR %08X\n", + tag, ERROR_ALLOC); + goto ERROR; + } + + if (byte_call == 0) { + index = 0; + snprintf(&driver_test_buff[index], 3, "{ "); + index += 2; + snprintf(&driver_test_buff[index], 9, "%08X", res); + + index += 8; + if (res >= OK) { + /*all the other cases are already fine printing only the res. */ + switch (funcToTest[0]) { + case CMD_VERSION: + case CMD_READ: + case CMD_WRITEREAD: + case CMD_WRITETHENWRITEREAD: + case CMD_WRITEREADU8UX: + case CMD_WRITEU8UXTHENWRITEREADU8UX: + case CMD_READCONFIG: + case CMD_POLLFOREVENT: + if (mess.dummy == 1) + j = 1; + else + j = 0; + for (; j < byteToRead + mess.dummy; j++) { + snprintf(&driver_test_buff[index], 3, "%02X", readData[j]); + index += 2; + } + break; + case CMD_GETFWFILE: + case CMD_GETLIMITSFILE: + logError(0, "%s Start To parse! \n", tag); + for (j = 0; j < fileSize; j++) { + snprintf(&driver_test_buff[index], 3, + "%02X", readData[j]); + index += 2; + } + logError(0, "%s Finish to parse! \n", tag); + break; + case CMD_GETFORCELEN: + case CMD_GETSENSELEN: + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) temp); + index += 2; + + break; + + case CMD_GETMSFRAME: + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) frameMS.header.force_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) frameMS.header.sense_node); + index += 2; + + for (j = 0; j < frameMS.node_data_size; j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (frameMS. + node_data[j] & 0xFF00) >> 8, + frameMS.node_data[j] & 0xFF); + index += 4; + } + + kfree(frameMS.node_data); + break; + + case CMD_GETSSFRAME: + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) frameSS.header.force_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) frameSS.header.sense_node); + index += 2; + for (j = 0; j < frameSS.header.force_node; j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (frameSS. + force_data[j] & 0xFF00) >> 8, + frameSS.force_data[j] & 0xFF); + index += 4; + } + + for (j = 0; j < frameSS.header.sense_node; j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (frameSS. + sense_data[j] & 0xFF00) >> 8, + frameSS.sense_data[j] & 0xFF); + index += 4; + } + + kfree(frameSS.force_data); + kfree(frameSS.sense_data); + break; + + case CMD_READMSCOMPDATA: + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) compData.header.type); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) compData.header.force_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) compData.header.sense_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + compData.cx1 & 0xFF); + index += 2; + + for (j = 0; j < compData.node_data_size; j++) { + snprintf(&driver_test_buff[index], 3, + "%02X", + compData.node_data[j] & 0xFF); + index += 2; + } + + kfree(compData.node_data); + break; + + case CMD_READSSCOMPDATA: + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) comData.header.type); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + comData.header.force_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + comData.header.sense_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + comData.f_ix1 & 0xFF); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + comData.s_ix1 & 0xFF); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + comData.f_cx1 & 0xFF); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + comData.s_cx1 & 0xFF); + index += 2; + + for (j = 0; j < comData.header.force_node; j++) { + snprintf(&driver_test_buff[index], 3, + "%02X", + comData.ix2_fm[j] & 0xFF); + index += 2; + + } + + for (j = 0; j < comData.header.sense_node; j++) { + snprintf(&driver_test_buff[index], 3, + "%02X", + comData.ix2_sn[j] & 0xFF); + index += 2; + + } + + for (j = 0; j < comData.header.force_node; j++) { + snprintf(&driver_test_buff[index], 3, + "%02X", + comData.cx2_fm[j] & 0xFF); + + index += 2; + } + + for (j = 0; j < comData.header.sense_node; j++) { + snprintf(&driver_test_buff[index], 3, + "%02X", + comData.cx2_sn[j] & 0xFF); + index += 2; + } + + kfree(comData.ix2_fm); + kfree(comData.ix2_sn); + kfree(comData.cx2_fm); + kfree(comData.cx2_sn); + break; + + case CMD_READTOTMSCOMPDATA: + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) totCompData.header.type); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) totCompData.header.force_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) totCompData.header.sense_node); + + index += 2; + + for (j = 0; j < totCompData.node_data_size; j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (totCompData. + node_data[j] & 0xFF00) >> 8, + totCompData. + node_data[j] & 0xFF); + index += 4; + } + + kfree(totCompData.node_data); + break; + + case CMD_READTOTSSCOMPDATA: + snprintf(&driver_test_buff[index], 3, "%02X", + (u8) totComData.header.type); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + totComData.header.force_node); + index += 2; + + snprintf(&driver_test_buff[index], 3, "%02X", + totComData.header.sense_node); + index += 2; + + for (j = 0; j < totComData.header.force_node; + j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (totComData. + ix_fm[j] & 0xFF00) >> 8, + totComData.ix_fm[j] & 0xFF); + index += 4; + } + + for (j = 0; j < totComData.header.sense_node; + j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (totComData. + ix_sn[j] & 0xFF00) >> 8, + totComData.ix_sn[j] & 0xFF); + index += 4; + } + + for (j = 0; j < totComData.header.force_node; + j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (totComData. + cx_fm[j] & 0xFF00) >> 8, + totComData.cx_fm[j] & 0xFF); + + index += 4; + } + + for (j = 0; j < totComData.header.sense_node; + j++) { + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (totComData. + cx_sn[j] & 0xFF00) >> 8, + totComData.cx_sn[j] & 0xFF); + index += 4; + } + + kfree(totComData.ix_fm); + kfree(totComData.ix_sn); + kfree(totComData.cx_fm); + kfree(totComData.cx_sn); + break; + + case CMD_GETFWVER: + snprintf(&driver_test_buff[index], 5, "%04X", + fw_version); + index += 4; + + snprintf(&driver_test_buff[index], 5, "%04X", + config_id); + index += 4; + break; + + case CMD_READCOMPDATAHEAD: + snprintf(&driver_test_buff[index], 3, "%02X", + dataHead.type); + index += 2; + break; + + default: + break; + } + } + + snprintf(&driver_test_buff[index], 4, " }\n"); + limit = size - 1; + printed = 0; + } else { + + driver_test_buff[index++] = MESSAGE_START_BYTE; + if (bin_output == 1) { + + driver_test_buff[index++] = (size & 0xFF00) >> 8; + driver_test_buff[index++] = (size & 0x00FF); + + driver_test_buff[index++] = + (mess.counter & 0xFF00) >> 8; + driver_test_buff[index++] = (mess.counter & 0x00FF); + + driver_test_buff[index++] = (mess.action & 0xFF00) >> 8; + driver_test_buff[index++] = (mess.action & 0x00FF); + + driver_test_buff[index++] = (res & 0xFF00) >> 8; + driver_test_buff[index++] = (res & 0x00FF); + + } else { + if (funcToTest[0] == CMD_GETLIMITSFILE_BYTE + || funcToTest[0] == CMD_GETFWFILE_BYTE) + snprintf(&driver_test_buff[index], 5, + "%02X%02X", + (((fileSize + 3) / 4) & 0xFF00) >> 8, + ((fileSize + 3) / 4) & 0x00FF); + else + snprintf(&driver_test_buff[index], 5, + "%02X%02X", (size & 0xFF00) >> 8, + size & 0xFF); + index += 4; + index += + snprintf(&driver_test_buff[index], 5, "%04X", + (u16) mess.counter); + index += + snprintf(&driver_test_buff[index], 5, "%04X", + (u16) mess.action); + index += + snprintf(&driver_test_buff[index], 5, "%02X%02X", + (res & 0xFF00) >> 8, res & 0xFF); + } + + switch (funcToTest[0]) { + case CMD_VERSION_BYTE: + case CMD_READ_BYTE: + case CMD_WRITEREAD_BYTE: + case CMD_WRITETHENWRITEREAD_BYTE: + case CMD_WRITEREADU8UX_BYTE: + case CMD_WRITEU8UXTHENWRITEREADU8UX_BYTE: + if (bin_output == 1) { + if (mess.dummy == 1) + memcpy(&driver_test_buff[index], + &readData[1], byteToRead); + else + memcpy(&driver_test_buff[index], + readData, byteToRead); + index += byteToRead; + } else { + j = mess.dummy; + for (; j < byteToRead + mess.dummy; j++) + index += + snprintf(&driver_test_buff[index], + 3, "%02X", + (u8) readData[j]); + } + break; + + case CMD_GETLIMITSFILE_BYTE: + case CMD_GETFWFILE_BYTE: + if (bin_output == 1) { + driver_test_buff[1] = + (((fileSize + 3) / 4) & 0xFF00) >> 8; + driver_test_buff[2] = + (((fileSize + 3) / 4) & 0x00FF); + + if (readData != NULL) { + memcpy(&driver_test_buff[index], + readData, fileSize); + } else { + logError(0, + "%s readData = NULL... returning junk data!", + tag); + } + index += addr; + } else { + for (j = 0; j < fileSize; j++) { + index += + snprintf(&driver_test_buff[index], + 3, "%02X", + (u8) readData[j]); + } + for (; j < addr; j++) + index += snprintf(&driver_test_buff[index], 3, "%02X", 0); + } + break; + default: + break; + } + + driver_test_buff[index++] = MESSAGE_END_BYTE; + driver_test_buff[index] = '\n'; + limit = size; + printed = 0; + } +ERROR: + numberParam = 0; + if (readData != NULL) + kfree(readData); + if (cmd) + kfree(cmd); + return count; +} + +/** @}*/ + +/** + * file_operations struct which define the functions for the canonical operation on a device file node (open. read, write etc.) + */ +static struct file_operations fts_driver_test_ops = { + .open = fts_open, + .read = seq_read, + .write = fts_driver_test_write, + .llseek = seq_lseek, + .release = seq_release +}; + +/*****************************************************************************/ + +/** +* This function is called in the probe to initialize and create the directory /proc/fts and the driver test file node DRIVER_TEST_FILE_NODE into the /proc file system +* @return OK if success or an error code which specify the type of error encountered +*/ +int fts_proc_init(void) +{ + struct proc_dir_entry *entry; + + int retval = 0; + + fts_dir = proc_mkdir_data("fts", 0777, NULL, NULL); + if (fts_dir == NULL) { + retval = -ENOMEM; + goto out; + } + + entry = proc_create(DRIVER_TEST_FILE_NODE, 0644, fts_dir, + &fts_driver_test_ops); + + if (entry) { + logError(1, "%s %s: proc entry CREATED! \n", tag, __func__); + } else { + logError(1, "%s %s: error creating proc entry! \n", tag, + __func__); + retval = -ENOMEM; + goto badfile; + } + return OK; +badfile: + remove_proc_entry("fts", NULL); +out: + return retval; +} + +/** +* Delete and Clean from the file system, all the references to the driver test file node +* @return OK +*/ +int fts_proc_remove(void) +{ + remove_proc_entry(DRIVER_TEST_FILE_NODE, fts_dir); + remove_proc_entry("fts", NULL); + return OK; +} diff --git a/drivers/leds/led-class.c b/drivers/leds/led-class.c index 79edd826e250..ea5aebe41f13 100644 --- a/drivers/leds/led-class.c +++ b/drivers/leds/led-class.c @@ -260,10 +260,14 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, if (ret < 0) return ret; + mutex_init(&led_cdev->led_access); + mutex_lock(&led_cdev->led_access); led_cdev->dev = device_create_with_groups(leds_class, parent, 0, led_cdev, led_cdev->groups, "%s", name); - if (IS_ERR(led_cdev->dev)) + if (IS_ERR(led_cdev->dev)) { + mutex_unlock(&led_cdev->led_access); return PTR_ERR(led_cdev->dev); + } led_cdev->dev->of_node = np; if (ret) @@ -274,6 +278,7 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, ret = led_add_brightness_hw_changed(led_cdev); if (ret) { device_unregister(led_cdev->dev); + mutex_unlock(&led_cdev->led_access); return ret; } } @@ -285,7 +290,6 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, #ifdef CONFIG_LEDS_BRIGHTNESS_HW_CHANGED led_cdev->brightness_hw_changed = -1; #endif - mutex_init(&led_cdev->led_access); /* add to the list of leds */ down_write(&leds_list_lock); list_add_tail(&led_cdev->node, &leds_list); @@ -302,6 +306,8 @@ int of_led_classdev_register(struct device *parent, struct device_node *np, led_trigger_set_default(led_cdev); #endif + mutex_unlock(&led_cdev->led_access); + dev_dbg(parent, "Registered led device: %s\n", led_cdev->name); @@ -317,6 +323,7 @@ EXPORT_SYMBOL_GPL(of_led_classdev_register); */ void led_classdev_unregister(struct led_classdev *led_cdev) { + mutex_lock(&led_cdev->led_access); #ifdef CONFIG_LEDS_TRIGGERS down_write(&led_cdev->trigger_lock); if (led_cdev->trigger) @@ -325,6 +332,8 @@ void led_classdev_unregister(struct led_classdev *led_cdev) #endif led_cdev->flags |= LED_UNREGISTERING; + led_sysfs_disable(led_cdev); + mutex_unlock(&led_cdev->led_access); /* Stop blinking */ led_stop_software_blink(led_cdev); @@ -341,8 +350,6 @@ void led_classdev_unregister(struct led_classdev *led_cdev) down_write(&leds_list_lock); list_del(&led_cdev->node); up_write(&leds_list_lock); - - mutex_destroy(&led_cdev->led_access); } EXPORT_SYMBOL_GPL(led_classdev_unregister); diff --git a/drivers/leds/leds-qti-tri-led.c b/drivers/leds/leds-qti-tri-led.c index b1d9319854f6..04fa7de13ce4 100644 --- a/drivers/leds/leds-qti-tri-led.c +++ b/drivers/leds/leds-qti-tri-led.c @@ -83,6 +83,14 @@ struct qpnp_tri_led_chip { u8 bitmap; }; +enum SYSFS_NODE{ + BREATH = 0, + STEP_MS, + PAUSE_LO, + LUT_PATTERN, + LO_IDX, +}; + static int qpnp_tri_led_read(struct qpnp_tri_led_chip *chip, u16 addr, u8 *val) { int rc; @@ -403,10 +411,176 @@ static const struct attribute *breath_attrs[] = { NULL }; +extern int qpnp_lpg_ramp_step_ms_get(struct pwm_device *pwm); +extern int qpnp_lpg_ramp_step_ms_set(struct pwm_device *pwm, u16 step_ms); + +static ssize_t step_ms_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + int step_ms; + + step_ms = qpnp_lpg_ramp_step_ms_get(led->pwm_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", step_ms); +} + +static ssize_t step_ms_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + u16 step_ms; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + rc = kstrtou16(buf, 0, &step_ms); + if (rc < 0) + return rc; + + mutex_lock(&led->lock); + + pr_debug("%s: step_ms set to %d\n", led->cdev.name, step_ms); + qpnp_lpg_ramp_step_ms_set(led->pwm_dev, step_ms); + + mutex_unlock(&led->lock); + return (rc < 0) ? rc : count; +} + +static DEVICE_ATTR(step_ms, 0644, step_ms_show, step_ms_store); +static const struct attribute *step_ms_attrs[] = { + &dev_attr_step_ms.attr, + NULL +}; + +extern int qpnp_lpg_pause_lo_count_get(struct pwm_device *pwm); +extern int qpnp_lpg_pause_lo_count_set(struct pwm_device *pwm, u8 pause_lo_count); + +static ssize_t pause_lo_count_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + u8 pause_lo_count; + + pause_lo_count = qpnp_lpg_pause_lo_count_get(led->pwm_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", pause_lo_count); +} + +static ssize_t pause_lo_count_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + u8 pause_lo_count; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + rc = kstrtou8(buf, 0, &pause_lo_count); + if (rc < 0) + return rc; + + mutex_lock(&led->lock); + + pr_debug("%s: pause_lo_count set to %d\n", led->cdev.name, pause_lo_count); + qpnp_lpg_pause_lo_count_set(led->pwm_dev, pause_lo_count); + + mutex_unlock(&led->lock); + return (rc < 0) ? rc : count; +} + +static DEVICE_ATTR(pause_lo_count, 0644, pause_lo_count_show, pause_lo_count_store); +static const struct attribute *pause_lo_count_attrs[] = { + &dev_attr_pause_lo_count.attr, + NULL +}; + +extern int qpnp_lpg_lo_idx_get(struct pwm_device *pwm); +extern int qpnp_lpg_lo_idx_set(struct pwm_device *pwm, u8 lo_idx); + +static ssize_t lo_idx_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + u8 lo_idx; + + lo_idx = qpnp_lpg_lo_idx_get(led->pwm_dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", lo_idx); +} + +static ssize_t lo_idx_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + u8 lo_idx; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + rc = kstrtou8(buf, 0, &lo_idx); + if (rc < 0) + return rc; + + mutex_lock(&led->lock); + + pr_debug("%s: lo_idx set to %d\n", led->cdev.name, lo_idx); + qpnp_lpg_lo_idx_set(led->pwm_dev, lo_idx); + + mutex_unlock(&led->lock); + return (rc < 0) ? rc : count; +} + +static DEVICE_ATTR(lo_idx, 0644, lo_idx_show, lo_idx_store); +static const struct attribute *lo_idx_attrs[] = { + &dev_attr_lo_idx.attr, + NULL +}; + +extern u8 qpnp_lpg_switch_lut_pattern(struct pwm_device *pwm, int index); + +static ssize_t lut_pattern_store(struct device *dev, struct device_attribute *attr, + const char *buf, size_t count) +{ + int rc; + int lut_pattern_index; + struct led_classdev *led_cdev = dev_get_drvdata(dev); + struct qpnp_led_dev *led = + container_of(led_cdev, struct qpnp_led_dev, cdev); + + rc = kstrtoint(buf, 0, &lut_pattern_index); + if (rc < 0) + return rc; + + mutex_lock(&led->lock); + + pr_debug("%s: lut_pattern switch to %d\n", led->cdev.name, lut_pattern_index); + qpnp_lpg_switch_lut_pattern(led->pwm_dev, lut_pattern_index); + + mutex_unlock(&led->lock); + return (rc < 0) ? rc : count; +} + +static DEVICE_ATTR(lut_pattern, 0644, NULL, lut_pattern_store); +static const struct attribute *lut_pattern_attrs[] = { + &dev_attr_lut_pattern.attr, + NULL +}; + static int qpnp_tri_led_register(struct qpnp_tri_led_chip *chip) { struct qpnp_led_dev *led; int rc, i, j; + int sysfs_index = 0; for (i = 0; i < chip->num_leds; i++) { led = &chip->leds[i]; @@ -431,21 +605,98 @@ static int qpnp_tri_led_register(struct qpnp_tri_led_chip *chip) & PWM_OUTPUT_MODULATED) { rc = sysfs_create_files(&led->cdev.dev->kobj, breath_attrs); + sysfs_index = BREATH; if (rc < 0) { dev_err(chip->dev, "Create breath file for %s led failed, rc=%d\n", led->label, rc); goto err_out; } } + + rc = sysfs_create_files(&led->cdev.dev->kobj, step_ms_attrs); + sysfs_index = STEP_MS; + if (rc < 0) { + dev_err(chip->dev, "Create step_ms file for %s led failed, rc=%d\n", + led->label, rc); + goto err_out; + } + + rc = sysfs_create_files(&led->cdev.dev->kobj, pause_lo_count_attrs); + sysfs_index = PAUSE_LO; + if (rc < 0) { + dev_err(chip->dev, "Create pause_lo_count file for %s led failed, rc=%d\n", + led->label, rc); + goto err_out; + } + + rc = sysfs_create_files(&led->cdev.dev->kobj, lut_pattern_attrs); + sysfs_index = LUT_PATTERN; + if (rc < 0) { + dev_err(chip->dev, "Create lut_pattern file for %s led failed, rc=%d\n", + led->label, rc); + goto err_out; + } + + rc = sysfs_create_files(&led->cdev.dev->kobj, lo_idx_attrs); + sysfs_index = LO_IDX; + if (rc < 0) { + dev_err(chip->dev, "Create lo_idx file for %s led failed, rc=%d\n", + led->label, rc); + goto err_out; + } } return 0; err_out: for (j = 0; j <= i; j++) { - if (j < i) + if (j < i) { sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, - breath_attrs); + breath_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + step_ms_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + pause_lo_count_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + lut_pattern_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + lo_idx_attrs); + } else { + switch (sysfs_index) { + case LO_IDX: + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + breath_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + step_ms_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + pause_lo_count_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + lut_pattern_attrs); + break; + case LUT_PATTERN: + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + breath_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + step_ms_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + pause_lo_count_attrs); + break; + case PAUSE_LO: + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + breath_attrs); + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + step_ms_attrs); + break; + case STEP_MS: + sysfs_remove_files(&chip->leds[j].cdev.dev->kobj, + breath_attrs); + break; + case BREATH: + default: + break; + } + } + mutex_destroy(&chip->leds[j].lock); } return rc; diff --git a/drivers/mailbox/msm_qmp.c b/drivers/mailbox/msm_qmp.c index ceb57d48d933..7994f7110e4b 100644 --- a/drivers/mailbox/msm_qmp.c +++ b/drivers/mailbox/msm_qmp.c @@ -967,7 +967,7 @@ static int qmp_mbox_probe(struct platform_device *pdev) mdev->name); ret = devm_request_irq(&pdev->dev, mdev->rx_irq_line, qmp_irq_handler, - IRQF_TRIGGER_RISING | IRQF_NO_SUSPEND | IRQF_SHARED, + IRQF_TRIGGER_RISING | IRQF_SHARED, edge_node->name, mdev); if (ret < 0) { qmp_mbox_remove(pdev); diff --git a/drivers/media/platform/msm/Kconfig b/drivers/media/platform/msm/Kconfig index bd35dd4f0bd5..977babc73f01 100644 --- a/drivers/media/platform/msm/Kconfig +++ b/drivers/media/platform/msm/Kconfig @@ -57,6 +57,14 @@ if MSMB_CAMERA source "drivers/media/platform/msm/camera_v2/Kconfig" endif # MSMB_CAMERA +config USE_ROHM_BU64753 + bool "use ROHM BU64753 acculator" + default n + +config VCM_AK7374 + bool "use ak7374 vcm" + default n + source "drivers/media/platform/msm/vidc/Kconfig" source "drivers/media/platform/msm/sde/Kconfig" source "drivers/media/platform/msm/npu/Kconfig" diff --git a/drivers/media/platform/msm/ais/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/ais/cam_sync/cam_sync_util.c index 5666218af76e..47cfa5cdf6a6 100644 --- a/drivers/media/platform/msm/ais/cam_sync/cam_sync_util.c +++ b/drivers/media/platform/msm/ais/cam_sync/cam_sync_util.c @@ -80,8 +80,23 @@ int cam_sync_init_group_object(struct sync_table_row *table, */ for (i = 0; i < num_objs; i++) { child_row = table + sync_objs[i]; + + if (idx == sync_objs[i]) { + CAM_ERR(CAM_SYNC, "invalid fence:%d should be released", + sync_objs[i]); + rc = -EINVAL; + goto clean_children_info; + } + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); + if (idx == sync_objs[i]) { + CAM_ERR(CAM_SYNC, "invalid fence:%d should be released", + sync_objs[i]); + rc = -EINVAL; + goto clean_children_info; + } + /* validate child */ if ((child_row->type == CAM_SYNC_TYPE_GROUP) || (child_row->state == CAM_SYNC_STATE_INVALID)) { diff --git a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 35645092aebf..3bf57bb931ce 100644 --- a/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/drivers/media/platform/msm/camera/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c @@ -51,6 +51,7 @@ #include "cam_trace.h" #include "cam_cpas_api.h" #include "cam_common_util.h" +#include "../cam_sync/cam_sync_private.h" #define ICP_WORKQ_TASK_CMD_TYPE 1 #define ICP_WORKQ_TASK_MSG_TYPE 2 @@ -58,7 +59,7 @@ #define ICP_DEV_TYPE_TO_CLK_TYPE(dev_type) \ ((dev_type == CAM_ICP_RES_TYPE_BPS) ? ICP_CLK_HW_BPS : ICP_CLK_HW_IPE) -#define ICP_DEVICE_IDLE_TIMEOUT 400 +#define ICP_DEVICE_IDLE_TIMEOUT 3000 static struct cam_icp_hw_mgr icp_hw_mgr; @@ -3482,6 +3483,22 @@ static bool cam_icp_mgr_is_valid_inconfig(struct cam_packet *packet) packet->num_io_configs, IPE_IO_IMAGES_MAX, num_in_map_entries, CAM_MAX_IN_RES); + /* + * From the input parameter side, we add the + * protection to avoid the kernel mem bort which + * introduced from userspace, since we have the + * limit on CAM_SYNC_MAX_OBJS for icp sync_obj num. + */ + for (i = 0 ; i < packet->num_io_configs; i++) { + if ((io_cfg_ptr[i].direction == CAM_BUF_INPUT) && + (io_cfg_ptr[i].fence >= CAM_SYNC_MAX_OBJS)) { + in_config_valid = false; + CAM_ERR(CAM_ICP, + "In config fence/sync_obj(%u) more than allowed(%u)", + io_cfg_ptr[i].fence, (CAM_SYNC_MAX_OBJS - 1)); + } + } + return in_config_valid; } diff --git a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c index cab3f74f1338..1e82039fbe23 100644 --- a/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c +++ b/drivers/media/platform/msm/camera/cam_isp/cam_isp_context.c @@ -572,8 +572,8 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( { int rc = 0; int i, j; - struct cam_ctx_request *req; - struct cam_isp_ctx_req *req_isp; + struct cam_ctx_request *req, *next_req; + struct cam_isp_ctx_req *req_isp, *next_req_isp; struct cam_context *ctx = ctx_isp->base; if (list_empty(&ctx->active_req_list)) { @@ -744,6 +744,30 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( ctx_isp->active_req_cnt--; } ctx_isp->irq_delay_detect = false; + if (ctx_isp->active_req_cnt > 0) { + if (list_empty(&ctx->active_req_list)) { + CAM_DBG(CAM_ISP, "Buf done with no active request!"); + goto end; + } + next_req = list_first_entry(&ctx->active_req_list, struct cam_ctx_request, list); + CAM_DBG(CAM_REQ, "next_req:%p, active_reqcnt:%d", next_req, ctx_isp->active_req_cnt); + + next_req_isp = (struct cam_isp_ctx_req *) next_req->req_priv; + + CAM_DBG(CAM_REQ, "next_req_isp:bubble_detected:%d,bubble_report:%d", + next_req_isp->bubble_detected, next_req_isp->bubble_report); + if (next_req_isp->bubble_detected && next_req_isp->bubble_report) { + next_req_isp->num_acked = 0; + next_req_isp->bubble_detected = false; + list_del_init(&next_req->list); + list_add(&next_req->list, &ctx->pending_req_list); + atomic_set(&ctx_isp->process_bubble, 0); + ctx_isp->active_req_cnt--; + CAM_DBG(CAM_REQ, + "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", + next_req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); + } + } end: return rc; } @@ -3365,6 +3389,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( list_add_tail(&req->list, &ctx->free_req_list); spin_unlock_bh(&ctx->lock); + atomic_set(&ctx_isp->process_bubble, 0); return rc; } diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c index 57731c13da66..7152f24a5908 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_core.c @@ -368,6 +368,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) int rc = 0; uint32_t val = 0, i; uint32_t status; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; csid_reg = csid_hw->csid_info->csid_reg; @@ -382,6 +383,7 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) CAM_DBG(CAM_ISP, "CSID:%d Csid reset", csid_hw->hw_intf->hw_idx); + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); /* Mask all interrupts */ cam_io_w_mb(0, soc_info->reg_map[0].mem_base + csid_reg->csi2_reg->csid_csi2_rx_irq_mask_addr); @@ -424,6 +426,8 @@ static int cam_ife_csid_global_reset(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + cam_io_w_mb(0x80, soc_info->reg_map[0].mem_base + csid_hw->csid_info->csid_reg->csi2_reg->csid_csi2_rx_cfg1_addr); @@ -1045,6 +1049,7 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) const struct cam_ife_csid_reg_offset *csid_reg; struct cam_hw_soc_info *soc_info; uint32_t i, val, clk_lvl; + unsigned long flags; csid_reg = csid_hw->csid_info->csid_reg; soc_info = &csid_hw->hw_info->soc_info; @@ -1083,6 +1088,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) goto disable_soc; } + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear all interrupts */ cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); @@ -1109,6 +1116,8 @@ static int cam_ife_csid_enable_hw(struct cam_ife_csid_hw *csid_hw) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + val = cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_hw_version_addr); CAM_DBG(CAM_ISP, "CSID:%d CSID HW version: 0x%x", @@ -2672,6 +2681,7 @@ static int cam_ife_csid_reset(void *hw_priv, csid_hw = (struct cam_ife_csid_hw *)csid_hw_info->core_info; reset = (struct cam_csid_reset_cfg_args *)reset_args; + mutex_lock(&csid_hw->hw_info->hw_mutex); switch (reset->reset_type) { case CAM_IFE_CSID_RESET_GLOBAL: rc = cam_ife_csid_global_reset(csid_hw); @@ -2685,6 +2695,7 @@ static int cam_ife_csid_reset(void *hw_priv, rc = -EINVAL; break; } + mutex_unlock(&csid_hw->hw_info->hw_mutex); return rc; } @@ -2827,9 +2838,13 @@ static int cam_ife_csid_reset_retain_sw_reg( const struct cam_ife_csid_reg_offset *csid_reg = csid_hw->csid_info->csid_reg; struct cam_hw_soc_info *soc_info; + unsigned long flags; soc_info = &csid_hw->hw_info->soc_info; /* clear the top interrupt first */ + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(1, soc_info->reg_map[0].mem_base + @@ -2838,6 +2853,9 @@ static int cam_ife_csid_reset_retain_sw_reg( cam_io_w_mb(csid_reg->cmn_reg->csid_rst_stb, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_rst_strobes_addr); + + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + rc = readl_poll_timeout(soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_status_addr, status, (status & 0x1) == 0x1, @@ -2851,11 +2869,16 @@ static int cam_ife_csid_reset_retain_sw_reg( csid_hw->hw_intf->hw_idx, rc); rc = 0; } + + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_top_irq_clear_addr); cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + return rc; } @@ -3563,6 +3586,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) cam_io_r_mb(soc_info->reg_map[0].mem_base + csid_reg->rdi_reg[i]->csid_rdi_irq_status_addr); + spin_lock_irqsave(&csid_hw->hw_info->hw_lock, flags); + /* clear */ cam_io_w_mb(irq_status[CSID_IRQ_STATUS_RX], soc_info->reg_map[0].mem_base + @@ -3585,6 +3610,8 @@ irqreturn_t cam_ife_csid_irq(int irq_num, void *data) cam_io_w_mb(1, soc_info->reg_map[0].mem_base + csid_reg->cmn_reg->csid_irq_cmd_addr); + spin_unlock_irqrestore(&csid_hw->hw_info->hw_lock, flags); + if (irq_status[CSID_IRQ_STATUS_RX] & BIT(csid_reg->csi2_reg->csi2_rst_done_shift_val)) { CAM_DBG(CAM_ISP, "csi rx reset complete"); diff --git a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c index 19c73f06c49f..2c3ce2022403 100644 --- a/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c +++ b/drivers/media/platform/msm/camera/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c @@ -436,7 +436,7 @@ void cam_isp_hw_get_timestamp(struct cam_isp_timestamp *time_stamp) { struct timespec ts; - get_monotonic_boottime(&ts); + ktime_get_ts(&ts); time_stamp->mono_time.tv_sec = ts.tv_sec; time_stamp->mono_time.tv_usec = ts.tv_nsec/1000; time_stamp->time_usecs = ts.tv_sec * 1000000 + diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c index 3bdc0f5e0b9f..fc12caccf674 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_actuator/cam_actuator_core.c @@ -407,6 +407,209 @@ int32_t cam_actuator_publish_dev_info(struct cam_req_mgr_device_info *info) return 0; } +#ifdef CONFIG_VCM_AK7374 +/* ---------------------------------------------------- +* Anti-Actuator-Noise logic start, +* Re-config actuator eeprom values +------------------------------------------------------*/ +#define AAN_AK7374_MASK 0xE8 +#define AAN_AK7374_WRITE_NUM 25 +#define AAN_AK7374_READ_NUM 22 + +unsigned int aan_already_write; + +unsigned int aan_ak7374_setting[AAN_AK7374_WRITE_NUM][2] = { + {0xAE, 0x3B}, {0x10, 0x36}, {0x11, 0x23}, {0x12, 0xDC}, + {0x13, 0x78}, {0x14, 0x14}, {0x15, 0x1E}, {0x16, 0x1A}, + {0x17, 0x5E}, {0x18, 0xDB}, {0x19, 0xC8}, {0x1A, 0x28}, + {0x1C, 0x00}, {0x1D, 0x00}, {0x1E, 0x00}, {0x20, 0x6E}, + {0x21, 0x01}, {0x22, 0x00}, {0x23, 0x1A}, {0x24, 0x00}, + {0x25, 0x00}, {0x03, 0x01}, {0x03, 0x02}, {0x03, 0x04}, + {0x03, 0x08} +}; + + /* +read-check: 0xE9,0x4B, 0x0 +write:0xE8,0xAE, 0x0 +power off +power on +wait 10ms + */ +unsigned int aan_ak7374_verify[AAN_AK7374_READ_NUM][2] = { + {0x0A, 0x89}, {0x0B, 0x84}, {0x10, 0x36}, {0x11, 0x23}, + {0x12, 0xDC}, {0x13, 0x78}, {0x14, 0x14}, {0x15, 0x1E}, + {0x16, 0x1A}, {0x17, 0x5E}, {0x18, 0xDB}, {0x19, 0xC8}, + {0x1A, 0x28}, {0x1C, 0x00}, {0x1D, 0x00}, {0x1E, 0x00}, + {0x20, 0x6E}, {0x21, 0x01}, {0x22, 0x00}, {0x23, 0x1A}, + {0x24, 0x00}, {0x25, 0x00} +}; + +static void aan_i2c_read(struct camera_io_master *io_master_info, struct i2c_settings_list *i2c_list, unsigned short addr, unsigned short *data) +{ + int rc = 0; + + i2c_list->i2c_settings.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_list->i2c_settings.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + + rc = camera_io_dev_read( + io_master_info, + addr, + (uint32_t *)(data), + i2c_list->i2c_settings.addr_type, + i2c_list->i2c_settings.data_type); + + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "aan, aan_i2c_read failed: %d", rc); + } else { + CAM_DBG(CAM_ACTUATOR, "aan, aan_i2c_read, addr=0x%x, data=0x%x, data_addr=0x%x, sid=0x%x", + addr, *data, data, io_master_info->cci_client->sid); + } +} + +static void aan_i2c_write(struct camera_io_master *io_master_info, struct i2c_settings_list *i2c_list, unsigned short addr, unsigned short data) +{ + int32_t rc = 0; + + i2c_list->i2c_settings.reg_setting[0].reg_addr = addr; + i2c_list->i2c_settings.reg_setting[0].reg_data = data; + i2c_list->i2c_settings.data_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_list->i2c_settings.addr_type = CAMERA_SENSOR_I2C_TYPE_BYTE; + i2c_list->op_code == CAM_SENSOR_I2C_WRITE_RANDOM; + i2c_list->i2c_settings.size = 1; + + rc = camera_io_dev_write(io_master_info, &(i2c_list->i2c_settings)); + if (rc < 0) { + CAM_ERR(CAM_ACTUATOR, "aan, aan_i2c_write failed: %d", rc); + } else { + CAM_DBG(CAM_ACTUATOR, "aan, aan_i2c_write, addr=0x%x, data=0x%x, sid=%d", addr, data, io_master_info->cci_client->sid); + } +} + +static int32_t cam_actuator_anti_noise(struct cam_actuator_ctrl_t *a_ctrl, struct i2c_settings_array *i2c_set) +{ + unsigned int i = 0; + unsigned short dat = 0; + struct i2c_settings_list *i2c_list; + unsigned int ret = 0; + unsigned int sid_backup; + + if (aan_already_write == 1) { + CAM_DBG(CAM_ACTUATOR, "aan, eeprom already set"); + return 0; + } else { + CAM_DBG(CAM_ACTUATOR, "aan, in"); + } + + if (a_ctrl != NULL && a_ctrl->io_master_info.cci_client != NULL) { + sid_backup = a_ctrl->io_master_info.cci_client->sid; + } else { + CAM_ERR(CAM_ACTUATOR, "aan, invalid param, a_ctrl or cci_client is NULL, a_ctrl=0x%p", a_ctrl); + return 0; + } + CAM_DBG(CAM_ACTUATOR, "aan, orig a_ctrl->io_master_info.cci_client->sid=%d", sid_backup); + + if ((AAN_AK7374_MASK >> 1) != a_ctrl->io_master_info.cci_client->sid) { + CAM_ERR(CAM_ACTUATOR, "aan, not 2nd provider module, no need update."); + return 0; + } + + if (a_ctrl == NULL || i2c_set == NULL) { + CAM_ERR(CAM_ACTUATOR, "aan, cam_actuator_anti_noise, Invalid Args"); + ret = -EINVAL; + goto aan_out; + } + + if (i2c_set->is_settings_valid != 1) { + CAM_ERR(CAM_ACTUATOR, "aan, cam_actuator_anti_noise, Invalid Args"); + ret = -EINVAL; + goto aan_out; + } + + list_for_each_entry(i2c_list, &(i2c_set->list_head), list) { + CAM_DBG(CAM_ACTUATOR, "aan, cam_actuator_anti_noise start. sid=%d, master_type=%d, i2c_set->request_id=%d", + a_ctrl->io_master_info.cci_client->sid, a_ctrl->io_master_info.master_type, i2c_set->request_id); + + // for 2nd provider AK7374 + a_ctrl->io_master_info.cci_client->sid = AAN_AK7374_MASK>>1; //AK7374 EEPROM mask + aan_i2c_read(&(a_ctrl->io_master_info), i2c_list, 0x03, &dat); + if (dat == 0x0E) { + //Step 1: Check whethre need to update the eeprom. + for (i = 0; i < AAN_AK7374_READ_NUM; i++) { + aan_i2c_read(&(a_ctrl->io_master_info), i2c_list, aan_ak7374_verify[i][0], &dat); + if (dat != aan_ak7374_verify[i][1]) { + CAM_ERR(CAM_ACTUATOR, "aan, eeprom data not match, i=%d, addr=0x%x, expect=0x%x, real=0x%x", + i, aan_ak7374_verify[i][0], aan_ak7374_verify[i][1], dat); + break; + } + } + if (i == AAN_AK7374_READ_NUM) { + CAM_ERR(CAM_ACTUATOR, "aan, do not need update"); + aan_already_write = 1; + goto aan_out; + } + + //Step 2: Update the eeprom PID. + for (i = 0; i < AAN_AK7374_WRITE_NUM; i++) { + aan_i2c_write(&(a_ctrl->io_master_info), i2c_list, aan_ak7374_setting[i][0], aan_ak7374_setting[i][1]); + if (0x03 == aan_ak7374_setting[i][0]) { + msleep(100); + } + } + + //Step 3: Check registers flag1 + aan_i2c_read(&(a_ctrl->io_master_info), i2c_list, 0x4B, &dat); + if (dat != 0) { + for (i = AAN_AK7374_WRITE_NUM-4; i < AAN_AK7374_WRITE_NUM; i++) { + aan_i2c_write(&(a_ctrl->io_master_info), i2c_list, aan_ak7374_setting[i][0], aan_ak7374_setting[i][1]); + } + aan_i2c_read(&(a_ctrl->io_master_info), i2c_list, 0x4B, &dat); + if (dat != 0) { + CAM_ERR(CAM_ACTUATOR, "aan, ak7374_write failed, 0x4B=0x%x", dat); + goto aan_out; + } + } + + //Step 4: Check register flag2 + aan_i2c_write(&(a_ctrl->io_master_info), i2c_list, 0x03, 0x10); + msleep(100); + aan_i2c_write(&(a_ctrl->io_master_info), i2c_list, 0xAE, 0x0); + msleep(100); + aan_i2c_read(&(a_ctrl->io_master_info), i2c_list, 0x0A, &dat); + if (dat != 0x89) { + CAM_ERR(CAM_ACTUATOR, "aan, ak7374 flag2 failed, 0x0A, expect=0x89, real=0x%x", dat); + } + CAM_DBG(CAM_ACTUATOR, "aan, ak7374_write done"); + + //Step 5: Verify PID data + for (i = 0; i < AAN_AK7374_READ_NUM; i++) { + aan_i2c_read(&(a_ctrl->io_master_info), i2c_list, aan_ak7374_verify[i][0], &dat); + if (dat != aan_ak7374_verify[i][1]) { + CAM_ERR(CAM_ACTUATOR, "aan, ak7374_write failed, i=%d, addr=0x%x,, expect=0x%x, real=0x%x", + i, aan_ak7374_verify[i][0], aan_ak7374_verify[i][1], dat); + break; + } + } + if (i == AAN_AK7374_READ_NUM) { + CAM_DBG(CAM_ACTUATOR, "aan, ak7374_write success."); + } else { + CAM_ERR(CAM_ACTUATOR, "aan, ak7374_write failed."); + } + goto aan_out; + } else { + CAM_ERR(CAM_ACTUATOR, "aan, not ak7374, 0x03=0x%x", dat); + } + } +aan_out: + a_ctrl->io_master_info.cci_client->sid = sid_backup; + aan_already_write = 1; + CAM_DBG(CAM_ACTUATOR, "aan, cam_actuator_anti_noise done"); + return 0; +} +/* ---------------------------------------------------- +* Anti-Actuator-Noise logic end +------------------------------------------------------*/ +#endif + int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, void *arg) { @@ -595,6 +798,10 @@ int32_t cam_actuator_i2c_pkt_parse(struct cam_actuator_ctrl_t *a_ctrl, goto rel_pkt_buf; } +#ifdef CONFIG_VCM_AK7374 + cam_actuator_anti_noise(a_ctrl, &a_ctrl->i2c_data.init_settings); +#endif + /* Delete the request even if the apply is failed */ rc = delete_request(&a_ctrl->i2c_data.init_settings); if (rc < 0) { diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c index a06a4c6c6339..9ab01270750d 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_core.c @@ -471,6 +471,8 @@ static int32_t cam_cci_calc_cmd_len(struct cci_device *cci_dev, for (i = 0; i < pack_max_len;) { if (cmd->delay || ((cmd - i2c_cmd) >= (cmd_size - 1))) break; + /* delete for E5G ois setting write */ +#ifndef CONFIG_USE_ROHM_BU64753 if (cmd->reg_addr + 1 == (cmd+1)->reg_addr) { len += data_len; @@ -479,7 +481,9 @@ static int32_t cam_cci_calc_cmd_len(struct cci_device *cci_dev, break; } (*pack)++; - } else { + } +#endif + else { break; } i += data_len; diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h index 2e4c032cb322..afeb7a4835bb 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_cci/cam_cci_dev.h @@ -46,7 +46,7 @@ #define CYCLES_PER_MICRO_SEC_DEFAULT 4915 #define CCI_MAX_DELAY 1000000 -#define CCI_TIMEOUT msecs_to_jiffies(1500) +#define CCI_TIMEOUT msecs_to_jiffies(500) #define NUM_MASTERS 2 #define NUM_QUEUES 2 diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c index b0901f83fa97..630abc8edd48 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_eeprom/cam_eeprom_core.c @@ -892,7 +892,13 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) rc = cam_eeprom_read_memory(e_ctrl, &e_ctrl->cal_data); if (rc) { CAM_ERR(CAM_EEPROM, - "read_eeprom_memory failed"); + "read_eeprom_memory failed, rc = %d", rc); + cam_destroy_device_hdl(e_ctrl->bridge_intf.device_hdl); + CAM_ERR(CAM_EEPROM, "destroying the device hdl"); + + e_ctrl->bridge_intf.device_hdl = -1; + e_ctrl->bridge_intf.link_hdl = -1; + e_ctrl->bridge_intf.session_hdl = -1; goto power_down; } @@ -932,7 +938,7 @@ static int32_t cam_eeprom_pkt_parse(struct cam_eeprom_ctrl_t *e_ctrl, void *arg) vfree(e_ctrl->cal_data.map); e_ctrl->cal_data.num_data = 0; e_ctrl->cal_data.num_map = 0; - e_ctrl->cam_eeprom_state = CAM_EEPROM_ACQUIRE; + e_ctrl->cam_eeprom_state = CAM_EEPROM_INIT; release_buf: if (cam_mem_put_cpu_buf(dev_config.packet_handle)) CAM_WARN(CAM_EEPROM, "Put cpu buffer failed : 0x%x", diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c index 937c46ab5033..24664bc8058f 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_ois/cam_ois_core.c @@ -63,6 +63,9 @@ int32_t cam_ois_construct_default_power_setting( } +#define CUSTOM_INIT_DL +#define OIS_TRANS_SIZE 64 + /** * cam_ois_get_dev_handle - get device handle * @o_ctrl: ctrl structure @@ -295,11 +298,45 @@ static int cam_ois_slaveInfo_pkt_parser(struct cam_ois_ctrl_t *o_ctrl, return rc; } +#ifdef CUSTOM_INIT_DL +struct cam_sensor_i2c_reg_array ois_init0_array[]= { + {0x8262, 0xFF02, 0x0, 0x0}, + {0x8263, 0x9F05, 0x0, 0x0}, + {0x8264, 0x6040, 0x0, 0x0}, + {0x8260, 0x1130, 0x0, 0x0}, + {0x8265, 0x8000, 0x0, 0x0}, + {0x8261, 0x0280, 0x0, 0x0}, + {0x8261, 0x0380, 0x0, 0x0}, + {0x8261, 0x0988, 0x0, 0x0}, +}; + +static int cam_ois_fw_init0(struct cam_ois_ctrl_t *o_ctrl) +{ + int32_t rc = 0; + struct cam_sensor_i2c_reg_setting write_setting; + write_setting.size= sizeof(ois_init0_array)/sizeof(struct cam_sensor_i2c_reg_array); + write_setting.addr_type =CAMERA_SENSOR_I2C_TYPE_WORD; + write_setting.data_type= CAMERA_SENSOR_I2C_TYPE_WORD; + write_setting.delay=0; + write_setting.reg_setting= ois_init0_array; + + rc = camera_io_dev_write(&(o_ctrl->io_master_info), + &write_setting); + if (rc < 0) { + CAM_ERR(CAM_OIS, + "{debug-ois}Failed in Applying i2c wrt settings"); + return rc; + } + + return rc; +} +#endif + static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) { uint16_t total_bytes = 0; uint8_t *ptr = NULL; - int32_t rc = 0, cnt; + int32_t rc = 0, cnt, i; uint32_t fw_size; const struct firmware *fw = NULL; const char *fw_name_prog = NULL; @@ -323,6 +360,10 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) fw_name_prog = name_prog; fw_name_coeff = name_coeff; +#ifdef CUSTOM_INIT_DL + cam_ois_fw_init0(o_ctrl); +#endif + /* Load FW */ rc = request_firmware(&fw, fw_name_prog, dev); if (rc) { @@ -348,20 +389,23 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( page_address(page)); - for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes; - cnt++, ptr++) { - i2c_reg_setting.reg_setting[cnt].reg_addr = - o_ctrl->opcode.prog; - i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; - i2c_reg_setting.reg_setting[cnt].delay = 0; - i2c_reg_setting.reg_setting[cnt].data_mask = 0; - } + for (i = 0, ptr = (uint8_t *)fw->data; i < total_bytes;) { + for (cnt = 0; cnt < OIS_TRANS_SIZE && i < total_bytes; + cnt++, ptr++, i++) { + i2c_reg_setting.reg_setting[cnt].reg_addr = + o_ctrl->opcode.prog; + i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; + i2c_reg_setting.reg_setting[cnt].delay = 0; + i2c_reg_setting.reg_setting[cnt].data_mask = 0; + } + i2c_reg_setting.size = cnt; - rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), - &i2c_reg_setting, 1); - if (rc < 0) { - CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); - goto release_firmware; + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 1); + if (rc < 0) { + CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); + goto release_firmware; + } } cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); @@ -393,20 +437,22 @@ static int cam_ois_fw_download(struct cam_ois_ctrl_t *o_ctrl) i2c_reg_setting.reg_setting = (struct cam_sensor_i2c_reg_array *) ( page_address(page)); - for (cnt = 0, ptr = (uint8_t *)fw->data; cnt < total_bytes; - cnt++, ptr++) { - i2c_reg_setting.reg_setting[cnt].reg_addr = - o_ctrl->opcode.coeff; - i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; - i2c_reg_setting.reg_setting[cnt].delay = 0; - i2c_reg_setting.reg_setting[cnt].data_mask = 0; - } - - rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), - &i2c_reg_setting, 1); - if (rc < 0) - CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); + for(i = 0, ptr = (uint8_t *)fw->data; i < total_bytes;) { + for (cnt = 0; cnt < OIS_TRANS_SIZE && i < total_bytes; + cnt++, ptr++, i++) { + i2c_reg_setting.reg_setting[cnt].reg_addr = + o_ctrl->opcode.coeff; + i2c_reg_setting.reg_setting[cnt].reg_data = *ptr; + i2c_reg_setting.reg_setting[cnt].delay = 0; + i2c_reg_setting.reg_setting[cnt].data_mask = 0; + } + i2c_reg_setting.size = cnt; + rc = camera_io_dev_write_continuous(&(o_ctrl->io_master_info), + &i2c_reg_setting, 1); + if (rc < 0) + CAM_ERR(CAM_OIS, "OIS FW download failed %d", rc); + } release_firmware: cma_release(dev_get_cma_area((o_ctrl->soc_info.dev)), page, fw_size); diff --git a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c index 7d048b982909..8ba37378b936 100644 --- a/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c +++ b/drivers/media/platform/msm/camera/cam_sensor_module/cam_sensor/cam_sensor_core.c @@ -646,6 +646,7 @@ int cam_sensor_match_id(struct cam_sensor_ctrl_t *s_ctrl) return rc; } +uint32_t g_operation_mode = 0; int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, void *arg) { @@ -773,6 +774,9 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, goto release_mutex; } + g_operation_mode = sensor_acq_dev.operation_mode; + CAM_DBG(CAM_SENSOR, "operation mode :%d", g_operation_mode); + bridge_params.session_hdl = sensor_acq_dev.session_handle; bridge_params.ops = &s_ctrl->bridge_intf.ops; bridge_params.v4l2_sub_dev_flag = 0; @@ -990,6 +994,98 @@ int32_t cam_sensor_driver_cmd(struct cam_sensor_ctrl_t *s_ctrl, } } break; + case CAM_UPDATE_REG: { + struct cam_sensor_i2c_reg_setting user_reg_setting; + struct cam_sensor_i2c_reg_array *i2c_reg_setting = NULL; + int i; + + rc = copy_from_user(&user_reg_setting, (void __user *)cmd->handle, sizeof(user_reg_setting)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Copy data from user space failed\n"); + goto release_mutex; + } + + CAM_DBG(CAM_SENSOR, "CAM_UPDATE_REG reg setting size = %d", user_reg_setting.size); + i2c_reg_setting = kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * + user_reg_setting.size, GFP_KERNEL); + if (!i2c_reg_setting) { + rc = -ENOMEM; + CAM_ERR(CAM_SENSOR, "kzalloc memory failed\n"); + goto release_mutex; + } + + rc = copy_from_user(i2c_reg_setting, (void __user *)user_reg_setting.reg_setting, + sizeof(struct cam_sensor_i2c_reg_array) * user_reg_setting.size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Copy i2c setting from user space failed\n"); + kfree(i2c_reg_setting); + goto release_mutex; + } + user_reg_setting.reg_setting = i2c_reg_setting; + + for (i = 0; i < user_reg_setting.size; i++) { + CAM_DBG(CAM_SENSOR, "CAM_UPDATE_REG reg_addr=0x%x, reg_value=0x%x", + i2c_reg_setting[i].reg_addr, i2c_reg_setting[i].reg_data); + } + + rc = camera_io_dev_write(&s_ctrl->io_master_info, &user_reg_setting); + if (rc < 0) + CAM_ERR(CAM_SENSOR, "Write setting failed, rc = %d\n", rc); + + kfree(i2c_reg_setting); + } + break; + case CAM_READ_REG: { + struct cam_sensor_i2c_reg_setting user_reg_setting; + struct cam_sensor_i2c_reg_array *i2c_reg_setting; + int ret = 0; + int i; + + rc = copy_from_user(&user_reg_setting, (void __user *)cmd->handle, sizeof(user_reg_setting)); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Copy data from user space failed"); + goto release_mutex; + } + + CAM_DBG(CAM_SENSOR, "CAM_READ_REG reg setting size = %d", user_reg_setting.size); + i2c_reg_setting = kzalloc(sizeof(struct cam_sensor_i2c_reg_array) * + user_reg_setting.size, GFP_KERNEL); + if (!i2c_reg_setting) { + rc = -ENOMEM; + CAM_ERR(CAM_SENSOR, "kzalloc memory failed\n"); + goto release_mutex; + } + + rc = copy_from_user(i2c_reg_setting, (void __user *)user_reg_setting.reg_setting, + sizeof(struct cam_sensor_i2c_reg_array) * user_reg_setting.size); + if (rc < 0) { + CAM_ERR(CAM_SENSOR, "Copy i2c setting from user space failed"); + kfree(i2c_reg_setting); + goto release_mutex; + } + + for (i = 0; i < user_reg_setting.size; i++) { + ret += camera_io_dev_read( + &(s_ctrl->io_master_info), + i2c_reg_setting[i].reg_addr, + &i2c_reg_setting[i].reg_data, CAMERA_SENSOR_I2C_TYPE_WORD, + CAMERA_SENSOR_I2C_TYPE_BYTE); + CAM_DBG(CAM_SENSOR, "CAM_READ_REG reg_addr=0x%x, reg_value=0x%x, sid = 0x%x", + i2c_reg_setting[i].reg_addr, i2c_reg_setting[i].reg_data, s_ctrl->io_master_info.cci_client->sid); + } + + if (copy_to_user((void __user *)user_reg_setting.reg_setting, i2c_reg_setting, + sizeof(struct cam_sensor_i2c_reg_array) * user_reg_setting.size) || ret != 0) { + CAM_ERR(CAM_SENSOR, "Copy data to user space failed"); + rc = -EFAULT; + } + if (copy_to_user((void __user *)cmd->handle, &user_reg_setting, sizeof(user_reg_setting)) || ret != 0) { + CAM_ERR(CAM_SENSOR, "Copy data to user space failed"); + rc = -EFAULT; + } + kfree(i2c_reg_setting); + } + break; default: CAM_ERR(CAM_SENSOR, "Invalid Opcode: %d", cmd->op_code); rc = -EINVAL; @@ -1029,12 +1125,17 @@ int cam_sensor_publish_dev_info(struct cam_req_mgr_device_info *info) info->dev_id = CAM_REQ_MGR_DEVICE_SENSOR; strlcpy(info->name, CAM_SENSOR_NAME, sizeof(info->name)); - if (s_ctrl->pipeline_delay >= 1 && s_ctrl->pipeline_delay <= 3) + if (s_ctrl->pipeline_delay >= 0 && s_ctrl->pipeline_delay <= 3) info->p_delay = s_ctrl->pipeline_delay; else info->p_delay = 2; info->trigger = CAM_TRIGGER_POINT_SOF; + if (g_operation_mode == 0x8006) + info->p_delay = 0; + if (g_operation_mode == 0x8002) + info->p_delay = 1; + return rc; } diff --git a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c index ae0b531a9169..9e93314ac594 100644 --- a/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c +++ b/drivers/media/platform/msm/camera/cam_smmu/cam_smmu_api.c @@ -2479,14 +2479,13 @@ static int cam_smmu_map_stage2_buffer_and_add_to_list(int idx, int ion_fd, /* add to the list */ list_add(&mapping_info->list, &iommu_cb_set.cb_info[idx].smmu_buf_list); - return 0; - err_unmap_sg: dma_buf_unmap_attachment(attach, table, dma_dir); err_detach: dma_buf_detach(dmabuf, attach); err_put: - dma_buf_put(dmabuf); + if (rc) + dma_buf_put(dmabuf); err_out: return rc; } diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h index c3cb345a13fa..382f81e8d41c 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_private.h @@ -31,7 +31,7 @@ #endif #define CAM_SYNC_OBJ_NAME_LEN 64 -#define CAM_SYNC_MAX_OBJS 1024 +#define CAM_SYNC_MAX_OBJS 1280 #define CAM_SYNC_MAX_V4L2_EVENTS 50 #define CAM_SYNC_DEBUG_FILENAME "cam_debug" #define CAM_SYNC_DEBUG_BASEDIR "cam" diff --git a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c index 5666218af76e..ede86c0ed2b7 100644 --- a/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c +++ b/drivers/media/platform/msm/camera/cam_sync/cam_sync_util.c @@ -80,6 +80,14 @@ int cam_sync_init_group_object(struct sync_table_row *table, */ for (i = 0; i < num_objs; i++) { child_row = table + sync_objs[i]; + + if (idx == sync_objs[i] || (sync_objs[i] >= CAM_SYNC_MAX_OBJS)) { + CAM_ERR(CAM_SYNC, "invalid fence:%d should be released", + sync_objs[i]); + rc = -EINVAL; + goto clean_children_info; + } + spin_lock_bh(&sync_dev->row_spinlocks[sync_objs[i]]); /* validate child */ diff --git a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h index d0bab027790e..be90a118b61c 100644 --- a/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h +++ b/drivers/media/platform/msm/camera/cam_utils/cam_soc_util.h @@ -36,7 +36,7 @@ #define CAM_SOC_MAX_BASE CAM_SOC_MAX_BLOCK /* maximum number of device regulator */ -#define CAM_SOC_MAX_REGULATOR 5 +#define CAM_SOC_MAX_REGULATOR 6 /* maximum number of device clock */ #define CAM_SOC_MAX_CLK 32 diff --git a/drivers/media/platform/msm/sde/Kconfig b/drivers/media/platform/msm/sde/Kconfig index 7a4f6301b9ce..58cb737c5efa 100644 --- a/drivers/media/platform/msm/sde/Kconfig +++ b/drivers/media/platform/msm/sde/Kconfig @@ -19,3 +19,8 @@ config MSM_SDE_ROTATOR_EVTLOG_DEBUG features to: Dump rotator registers during driver errors, panic driver during fatal errors and enable some rotator driver logging into an internal buffer (this avoids logging overhead). + +config MSM_SDE_ROTATOR_XLOG_DEBUG + bool "Trigger a panic after the dumping work has completed when SDE ROTATOR error" + default n + depends on MSM_SDE_ROTATOR diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c index 3223d51af83d..5b612f79fa6e 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_debug.c @@ -28,10 +28,18 @@ #else #define SDE_EVTLOG_DEFAULT_ENABLE 0 #endif + +#ifdef CONFIG_MSM_SDE_ROTATOR_XLOG_DEBUG #define SDE_EVTLOG_DEFAULT_PANIC 1 #define SDE_EVTLOG_DEFAULT_REGDUMP SDE_ROT_DBG_DUMP_IN_MEM #define SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM #define SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_MEM +#else +#define SDE_EVTLOG_DEFAULT_PANIC 0 +#define SDE_EVTLOG_DEFAULT_REGDUMP SDE_ROT_DBG_DUMP_IN_LOG +#define SDE_EVTLOG_DEFAULT_VBIF_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_LOG +#define SDE_EVTLOG_DEFAULT_ROT_DBGBUSDUMP SDE_ROT_DBG_DUMP_IN_LOG +#endif /* * evtlog will print this number of entries when it is called through diff --git a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c index c8daa5b5ed49..0801c91c2b75 100644 --- a/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c +++ b/drivers/media/platform/msm/sde/rotator/sde_rotator_dev.c @@ -3683,6 +3683,8 @@ static int sde_rotator_probe(struct platform_device *pdev) rot_dev->kthread_free[i] = true; } + device_enable_async_suspend(&pdev->dev); + SDEDEV_INFO(&pdev->dev, "SDE v4l2 rotator probe success\n"); return 0; diff --git a/drivers/media/platform/msm/vidc/msm_vidc_debug.c b/drivers/media/platform/msm/vidc/msm_vidc_debug.c index a9bea9522cdf..517a33915c29 100644 --- a/drivers/media/platform/msm/vidc/msm_vidc_debug.c +++ b/drivers/media/platform/msm/vidc/msm_vidc_debug.c @@ -24,7 +24,7 @@ EXPORT_SYMBOL(msm_vidc_debug_out); /* 0x18 = HFI_DEBUG_MSG_FATAL | HFI_DEBUG_MSG_ERROR */ int msm_vidc_fw_debug = 0x18; -int msm_vidc_fw_debug_mode = 1; +int msm_vidc_fw_debug_mode = 0; int msm_vidc_fw_low_power_mode = 1; bool msm_vidc_fw_coverage = !true; bool msm_vidc_thermal_mitigation_disabled = !true; diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig index 6af8fcae1600..57057bb39226 100644 --- a/drivers/media/rc/Kconfig +++ b/drivers/media/rc/Kconfig @@ -485,7 +485,7 @@ endif #RC_DEVICES config IR_MSM_GENI tristate "MSM GENI IR Controller" depends on RC_CORE - default m + default n ---help--- Say Y here to enable support for integrated infrared module for MSM family processors. diff --git a/drivers/media/rc/ir-spi.c b/drivers/media/rc/ir-spi.c index 29ed0638cb74..49363ca87ee1 100644 --- a/drivers/media/rc/ir-spi.c +++ b/drivers/media/rc/ir-spi.c @@ -9,181 +9,297 @@ * SPI driven IR LED device driver */ -#include #include #include #include #include #include #include -#include +#include "media/lirc_dev.h" #define IR_SPI_DRIVER_NAME "ir-spi" -/* pulse value for different duty cycles */ -#define IR_SPI_PULSE_DC_50 0xff00 -#define IR_SPI_PULSE_DC_60 0xfc00 -#define IR_SPI_PULSE_DC_70 0xf800 -#define IR_SPI_PULSE_DC_75 0xf000 -#define IR_SPI_PULSE_DC_80 0xc000 -#define IR_SPI_PULSE_DC_90 0x8000 - -#define IR_SPI_DEFAULT_FREQUENCY 38000 -#define IR_SPI_BIT_PER_WORD 8 -#define IR_SPI_MAX_BUFSIZE 4096 +#define IR_SPI_DEFAULT_FREQUENCY 1920000 +#define IR_SPI_BIT_PER_WORD 32 +#define IR_SPI_DATA_BUFFER 150000 struct ir_spi_data { - u32 freq; - u8 duty_cycle; - bool negated; + u16 nusers; + int power_gpio; + int buffer_size; - u16 tx_buf[IR_SPI_MAX_BUFSIZE]; - u16 pulse; - u16 space; + u8 *buffer; - struct rc_dev *rc; + struct lirc_driver lirc_driver; struct spi_device *spi; + struct spi_transfer xfer; + struct mutex mutex; struct regulator *regulator; }; -static int ir_spi_tx(struct rc_dev *dev, - unsigned int *buffer, unsigned int count) +static ssize_t ir_spi_chardev_write(struct file *file, + const char __user *buffer, + size_t length, loff_t *offset) { - int i; - int ret; - unsigned int len = 0; - struct ir_spi_data *idata = dev->priv; - struct spi_transfer xfer; - - /* convert the pulse/space signal to raw binary signal */ - for (i = 0; i < count; i++) { - unsigned int periods; - int j; - u16 val; + struct ir_spi_data *idata = file->private_data; + bool please_free = false; + int ret = 0; - periods = DIV_ROUND_CLOSEST(buffer[i] * idata->freq, 1000000); + if (idata->xfer.len && (idata->xfer.len != length)) + return -EINVAL; - if (len + periods >= IR_SPI_MAX_BUFSIZE) - return -EINVAL; + mutex_lock(&idata->mutex); - /* - * the first value in buffer is a pulse, so that 0, 2, 4, ... - * contain a pulse duration. On the contrary, 1, 3, 5, ... - * contain a space duration. - */ - val = (i % 2) ? idata->space : idata->pulse; - for (j = 0; j < periods; j++) - idata->tx_buf[len++] = val; - } + if (!idata->xfer.len) { + idata->buffer = kmalloc(length, GFP_DMA); - memset(&xfer, 0, sizeof(xfer)); + if (!idata->buffer) { + ret = -ENOMEM; + goto out_unlock; + } - xfer.speed_hz = idata->freq * 16; - xfer.len = len * sizeof(*idata->tx_buf); - xfer.tx_buf = idata->tx_buf; + idata->xfer.len = length; + please_free = true; + } + if (copy_from_user(idata->buffer, buffer, length)) { + ret = -EFAULT; + goto out_free; + } +#if 0 ret = regulator_enable(idata->regulator); - if (ret) - return ret; - - ret = spi_sync_transfer(idata->spi, &xfer, 1); + if (ret) { + dev_err(&idata->spi->dev, "failed to power on the LED\n"); + goto out_free; + } +#endif + idata->xfer.tx_buf = idata->buffer; + dev_warn(&idata->spi->dev, "xfer.len%d buffer_size %d\n",(int)idata->xfer.len,idata->buffer_size); + ret = spi_sync_transfer(idata->spi, &idata->xfer, 1); if (ret) dev_err(&idata->spi->dev, "unable to deliver the signal\n"); - +#if 0 regulator_disable(idata->regulator); +#endif +out_free: + if (please_free) { + kfree(idata->buffer); + idata->xfer.len = 0; + idata->buffer = NULL; + } + +out_unlock: + mutex_unlock(&idata->mutex); - return ret ? ret : count; + return ret ? ret : length; } -static int ir_spi_set_tx_carrier(struct rc_dev *dev, u32 carrier) +static int ir_spi_chardev_open(struct inode *inode, struct file *file) { - struct ir_spi_data *idata = dev->priv; + struct ir_spi_data *idata = lirc_get_pdata(file); - if (!carrier) - return -EINVAL; + if (unlikely(idata->nusers >= SHRT_MAX)) { + dev_err(&idata->spi->dev, "device busy\n"); + return -EBUSY; + } - idata->freq = carrier; + file->private_data = idata; + + mutex_lock(&idata->mutex); + idata->nusers++; + mutex_unlock(&idata->mutex); return 0; } -static int ir_spi_set_duty_cycle(struct rc_dev *dev, u32 duty_cycle) +static int ir_spi_chardev_close(struct inode *inode, struct file *file) { - struct ir_spi_data *idata = dev->priv; - - if (duty_cycle >= 90) - idata->pulse = IR_SPI_PULSE_DC_90; - else if (duty_cycle >= 80) - idata->pulse = IR_SPI_PULSE_DC_80; - else if (duty_cycle >= 75) - idata->pulse = IR_SPI_PULSE_DC_75; - else if (duty_cycle >= 70) - idata->pulse = IR_SPI_PULSE_DC_70; - else if (duty_cycle >= 60) - idata->pulse = IR_SPI_PULSE_DC_60; - else - idata->pulse = IR_SPI_PULSE_DC_50; - - if (idata->negated) { - idata->pulse = ~idata->pulse; - idata->space = 0xffff; - } else { - idata->space = 0; + struct ir_spi_data *idata = lirc_get_pdata(file); + + mutex_lock(&idata->mutex); + idata->nusers--; + + /* + * check if someone else is using the driver, + * if not, then: + * + * - reset length and frequency values to default + * - shut down the LED + * - free the buffer (NULL or ZERO_SIZE_PTR are noop) + */ + if (!idata->nusers) { + idata->xfer.len = 0; + idata->xfer.speed_hz = IR_SPI_DEFAULT_FREQUENCY; } + mutex_unlock(&idata->mutex); + return 0; } +static long ir_spi_chardev_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + __u32 p; + s32 ret; + struct ir_spi_data *idata = file->private_data; + + switch (cmd) { + case LIRC_GET_FEATURES: + return put_user(idata->lirc_driver.features, + (__u32 __user *) arg); + + case LIRC_GET_LENGTH: + return put_user(idata->xfer.len, (__u32 __user *) arg); + + case LIRC_SET_SEND_MODE: { + void *new; + + ret = get_user(p, (__u32 __user *) arg); + if (ret) + return ret; + + /* + * the user is trying to set the same + * length of the current value + */ + if (idata->xfer.len == p) + return 0; + + /* + * multiple users should use the driver with the + * length, otherwise return EPERM same data + */ + if (idata->nusers > 1) + return -EPERM; + + /* + * if the buffer is already allocated, reallocate it with the + * desired value. If the desired value is 0, then the buffer is + * freed from krealloc() + */ + if (idata->xfer.len){ + new = krealloc(idata->buffer, p, GFP_DMA); + } + else{ + if ((p>idata->buffer_size) || (idata->buffer == NULL)){ + printk ("IR new malloc %d",(int)idata->xfer.len); + if (idata->buffer != NULL) + { + kfree (idata->buffer); + idata->buffer = NULL; + } + new = kmalloc(p, GFP_DMA); + if (!new) + return -ENOMEM; + idata->buffer = new; + idata->buffer_size = p; + } + } + + mutex_lock(&idata->mutex); + idata->xfer.len = p; + mutex_unlock(&idata->mutex); + + return 0; + } + + case LIRC_SET_SEND_CARRIER: + return put_user(idata->xfer.speed_hz, (__u32 __user *) arg); + + case LIRC_SET_REC_CARRIER: + ret = get_user(p, (__u32 __user *) arg); + if (ret) + return ret; + + /* + * The frequency cannot be obviously set to '0', + * while, as in the case of the data length, + * multiple users should use the driver with the same + * frequency value, otherwise return EPERM + */ + if (!p || ((idata->nusers > 1) && p != idata->xfer.speed_hz)) + return -EPERM; + + mutex_lock(&idata->mutex); + idata->xfer.speed_hz = p; + mutex_unlock(&idata->mutex); + return 0; + } + + return -EINVAL; +} + +static const struct file_operations ir_spi_fops = { + .owner = THIS_MODULE, + .read = lirc_dev_fop_read, + .write = ir_spi_chardev_write, + .poll = lirc_dev_fop_poll, + .open = ir_spi_chardev_open, + .release = ir_spi_chardev_close, + .llseek = noop_llseek, + .unlocked_ioctl = ir_spi_chardev_ioctl, + .compat_ioctl = ir_spi_chardev_ioctl, +}; + static int ir_spi_probe(struct spi_device *spi) { - int ret; - u8 dc; struct ir_spi_data *idata; - + u8 *buffer = NULL; idata = devm_kzalloc(&spi->dev, sizeof(*idata), GFP_KERNEL); if (!idata) return -ENOMEM; - +#if 0 idata->regulator = devm_regulator_get(&spi->dev, "irda_regulator"); if (IS_ERR(idata->regulator)) return PTR_ERR(idata->regulator); +#endif + snprintf(idata->lirc_driver.name, sizeof(idata->lirc_driver.name), + IR_SPI_DRIVER_NAME); + idata->lirc_driver.features = LIRC_CAN_SEND_RAW; + idata->lirc_driver.code_length = 1; + idata->lirc_driver.fops = &ir_spi_fops; + idata->lirc_driver.dev = &spi->dev; + idata->lirc_driver.data = idata; + idata->lirc_driver.owner = THIS_MODULE; + idata->lirc_driver.minor = -1; + + idata->lirc_driver.minor = lirc_register_driver(&idata->lirc_driver); + if (idata->lirc_driver.minor < 0) { + dev_err(&spi->dev, "unable to generate character device\n"); + return idata->lirc_driver.minor; + } - idata->rc = devm_rc_allocate_device(&spi->dev, RC_DRIVER_IR_RAW_TX); - if (!idata->rc) - return -ENOMEM; - - idata->rc->tx_ir = ir_spi_tx; - idata->rc->s_tx_carrier = ir_spi_set_tx_carrier; - idata->rc->s_tx_duty_cycle = ir_spi_set_duty_cycle; - idata->rc->device_name = "IR SPI"; - idata->rc->driver_name = IR_SPI_DRIVER_NAME; - idata->rc->priv = idata; - idata->spi = spi; - - idata->negated = of_property_read_bool(spi->dev.of_node, - "led-active-low"); - ret = of_property_read_u8(spi->dev.of_node, "duty-cycle", &dc); - if (ret) - dc = 50; - - /* ir_spi_set_duty_cycle cannot fail, - * it returns int to be compatible with the - * rc->s_tx_duty_cycle function - */ - ir_spi_set_duty_cycle(idata->rc, dc); + mutex_init(&idata->mutex); - idata->freq = IR_SPI_DEFAULT_FREQUENCY; + idata->spi = spi; - return devm_rc_register_device(&spi->dev, idata->rc); + idata->xfer.bits_per_word = IR_SPI_BIT_PER_WORD; + idata->xfer.speed_hz = IR_SPI_DEFAULT_FREQUENCY; + buffer = kmalloc(IR_SPI_DATA_BUFFER, GFP_DMA); + if (!buffer) + { + return -ENOMEM; + } + idata->buffer = buffer; + idata->buffer_size = IR_SPI_DATA_BUFFER; + return 0; } static int ir_spi_remove(struct spi_device *spi) { + struct ir_spi_data *idata = spi_get_drvdata(spi); + if (idata->buffer != NULL){ + kfree(idata->buffer); + idata->buffer = NULL; + } + lirc_unregister_driver(idata->lirc_driver.minor); + return 0; } static const struct of_device_id ir_spi_of_match[] = { - { .compatible = "ir-spi-led" }, + { .compatible = "ir-spi" }, {}, }; diff --git a/drivers/media/usb/gspca/Kconfig b/drivers/media/usb/gspca/Kconfig index 3fd94fe7e1eb..498aadd3b3c8 100644 --- a/drivers/media/usb/gspca/Kconfig +++ b/drivers/media/usb/gspca/Kconfig @@ -2,7 +2,7 @@ menuconfig USB_GSPCA tristate "GSPCA based webcams" depends on VIDEO_V4L2 depends on INPUT || INPUT=n - default m + default n ---help--- Say Y here if you want to enable selecting webcams based on the GSPCA framework. diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c index e329e918b143..15725de2a4e3 100644 --- a/drivers/media/v4l2-core/v4l2-ioctl.c +++ b/drivers/media/v4l2-core/v4l2-ioctl.c @@ -2923,7 +2923,7 @@ long video_usercopy(struct file *file, unsigned int cmd, unsigned long arg, v4l2_kioctl func) { - char sbuf[128]; + char sbuf[SZ_1K]; void *mbuf = NULL; void *parg = (void *)arg; long err = -EINVAL; diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile index aef0d81d77c6..8405c09df6f1 100644 --- a/drivers/mfd/Makefile +++ b/drivers/mfd/Makefile @@ -228,3 +228,5 @@ obj-$(CONFIG_MFD_SUN4I_GPADC) += sun4i-gpadc.o obj-$(CONFIG_MFD_STM32_LPTIMER) += stm32-lptimer.o obj-$(CONFIG_MFD_STM32_TIMERS) += stm32-timers.o obj-$(CONFIG_MFD_MXS_LRADC) += mxs-lradc.o + +obj-y += spk-id.o diff --git a/drivers/mfd/spk-id.c b/drivers/mfd/spk-id.c new file mode 100644 index 000000000000..e483d0c8e724 --- /dev/null +++ b/drivers/mfd/spk-id.c @@ -0,0 +1,208 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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 + + +struct spk_id_info { + struct pinctrl *pinctrl; + struct pinctrl_state *pull_down; + struct pinctrl_state *pull_up; + struct pinctrl_state *no_pull; + int gpio; + int state; +}; + + +static struct spk_id_info *spk_id_get_info(struct device_node *np) +{ + struct platform_device *pdev; + struct spk_id_info *info; + + if (!np) { + pr_err("%s: device node is null\n", __func__); + return NULL; + } + + pdev = of_find_device_by_node(np); + if (!pdev) { + pr_err("%s: platform device not found!\n", __func__); + return NULL; + } + + info = dev_get_drvdata(&pdev->dev); + if (!info) + dev_err(&pdev->dev, "%s: cannot find spk id info\n", __func__); + + return info; +} + +int spk_id_get_pin_3state(struct device_node *np) +{ + struct spk_id_info *info; + int pu = 0; + int pd = 0; + + info = spk_id_get_info(np); + if (!info) + return -EINVAL; + + if (IS_ERR_OR_NULL(info->pinctrl)) { + pr_err("%s: pin ctrl is invalid:%ld\n", __func__, PTR_ERR(info->pinctrl)); + return -EINVAL; + } + + if (!gpio_is_valid(info->gpio)) { + pr_err("%s: gpio is invalid:%d\n", __func__, info->gpio); + return -EINVAL; + } + + pinctrl_select_state(info->pinctrl, info->pull_down); + msleep(3); + pd = gpio_get_value(info->gpio); + + pinctrl_select_state(info->pinctrl, info->pull_up); + msleep(3); + pu = gpio_get_value(info->gpio); + + + if ((pd == pu) && (pd == 0)) { + pr_info("%s: id pin%d = %d\n", __func__, info->gpio, pd); + pinctrl_select_state(info->pinctrl, info->pull_down); + info->state = PIN_PULL_DOWN; + } else if ((pd == pu) && (pd == 1)) { + pr_info("%s: id pin%d = %d\n", __func__, info->gpio, pd); + pinctrl_select_state(info->pinctrl, info->pull_up); + info->state = PIN_PULL_UP; + } else { + pr_info("%s: id pin%d = 2\n", __func__, info->gpio); + pinctrl_select_state(info->pinctrl, info->no_pull); + info->state = PIN_FLOAT; + } + + return info->state; +} +EXPORT_SYMBOL(spk_id_get_pin_3state); + +static int spk_id_probe(struct platform_device *pdev) +{ + int ret = 0; + struct spk_id_info *info; + + info = devm_kzalloc(&pdev->dev, + sizeof(struct spk_id_info), + GFP_KERNEL); + if (!info) + return -ENOMEM; + + dev_dbg(&pdev->dev, "%s: device %s\n", __func__, pdev->name); + info->pinctrl = devm_pinctrl_get(&pdev->dev); + if (IS_ERR_OR_NULL(info->pinctrl)) { + dev_err(&pdev->dev, "%s: Cannot get speaker id gpio pinctrl:%ld\n", + __func__, PTR_ERR(info->pinctrl)); + ret = PTR_ERR(info->pinctrl); + goto err_pctrl_get; + } + + info->pull_down = pinctrl_lookup_state( + info->pinctrl, "pull_down"); + if (IS_ERR_OR_NULL(info->pull_down)) { + dev_err(&pdev->dev, "%s: Cannot get pull_down pinctrl state:%ld\n", + __func__, PTR_ERR(info->pull_down)); + ret = PTR_ERR(info->pull_down); + goto err_lookup_state; + } + + info->pull_up = pinctrl_lookup_state( + info->pinctrl, "pull_up"); + if (IS_ERR_OR_NULL(info->pull_up)) { + dev_err(&pdev->dev, "%s: Cannot get pull_up pinctrl state:%ld\n", + __func__, PTR_ERR(info->pull_up)); + ret = PTR_ERR(info->pull_up); + goto err_lookup_state; + } + + info->no_pull = pinctrl_lookup_state( + info->pinctrl, "no_pull"); + if (IS_ERR_OR_NULL(info->no_pull)) { + dev_err(&pdev->dev, "%s: Cannot get no_pull pinctrl state:%ld\n", + __func__, PTR_ERR(info->no_pull)); + ret = PTR_ERR(info->no_pull); + goto err_lookup_state; + } + + info->gpio = of_get_named_gpio(pdev->dev.of_node, + "audio,speaker-id-gpio", 0); + if (gpio_is_valid(info->gpio)) { + ret = gpio_request(info->gpio, "speaker-id"); + if (ret) { + dev_err(&pdev->dev, "%s: Failed to request gpio %d\n", + __func__, info->gpio); + goto err_lookup_state; + } + } + + dev_set_drvdata(&pdev->dev, info); + return 0; + +err_lookup_state: + devm_pinctrl_put(info->pinctrl); +err_pctrl_get: + devm_kfree(&pdev->dev, info); + return ret; +} + +static int spk_id_remove(struct platform_device *pdev) +{ + struct spk_id_info *info; + + info = dev_get_drvdata(&pdev->dev); + + if (info) { + if (info->pinctrl) + devm_pinctrl_put(info->pinctrl); + if (gpio_is_valid(info->gpio)) + gpio_free(info->gpio); + } + + devm_kfree(&pdev->dev, info); + return 0; +} + +static const struct of_device_id spk_id_match[] = { + {.compatible = "audio,speaker-id"}, + {} +}; + +static struct platform_driver spk_id_driver = { + .driver = { + .name = "spk-id", + .owner = THIS_MODULE, + .of_match_table = spk_id_match, + }, + .probe = spk_id_probe, + .remove = spk_id_remove, +}; +module_platform_driver(spk_id_driver); + +MODULE_DESCRIPTION("Speaker ID platform driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/nfc/nq-nci.c b/drivers/nfc/nq-nci.c index 19829a9a8623..b9b3824bd19e 100644 --- a/drivers/nfc/nq-nci.c +++ b/drivers/nfc/nq-nci.c @@ -793,6 +793,12 @@ static const struct file_operations nfc_dev_fops = { #endif }; +/** + * Do not need check availability of NFCC. + * This function will block NFCC to enter FW download mode. + */ + +#if 0 /* Check for availability of NQ_ NFC controller hardware */ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) { @@ -1007,6 +1013,7 @@ static int nfcc_hw_check(struct i2c_client *client, struct nqx_dev *nqx_dev) return ret; } +#endif /* * Routine to enable clock. @@ -1326,13 +1333,15 @@ static int nqx_probe(struct i2c_client *client, /* NFC_INT IRQ */ nqx_dev->irq_enabled = true; r = request_irq(client->irq, nqx_dev_irq_handler, - IRQF_TRIGGER_HIGH, client->name, nqx_dev); + IRQF_TRIGGER_RISING, client->name, nqx_dev); if (r) { dev_err(&client->dev, "%s: request_irq failed\n", __func__); goto err_request_irq_failed; } nqx_disable_irq(nqx_dev); + /* Do not perform nfcc_hw_check, make sure that nfcc is present */ +#if 0 /* * To be efficient we need to test whether nfcc hardware is physically * present before attempting further hardware initialisation. @@ -1345,6 +1354,7 @@ static int nqx_probe(struct i2c_client *client, /* We don't think there is hardware switch NFC OFF */ goto err_request_hw_check_failed; } +#endif /* Register reboot notifier here */ r = register_reboot_notifier(&nfcc_notifier); @@ -1360,11 +1370,13 @@ static int nqx_probe(struct i2c_client *client, } #ifdef NFC_KERNEL_BU - r = nqx_clock_select(nqx_dev); - if (r < 0) { - dev_err(&client->dev, - "%s: nqx_clock_select failed\n", __func__); - goto err_clock_en_failed; + if (nqx_dev->pdata->clk_pin_voting) { + r = nqx_clock_select(nqx_dev); + if (r < 0) { + dev_err(&client->dev, + "%s: nqx_clock_select failed\n", __func__); + goto err_clock_en_failed; + } } gpio_set_value(platform_data->en_gpio, 1); #endif diff --git a/drivers/of/of_batterydata.c b/drivers/of/of_batterydata.c index b275a8c0aad0..054c5ae9883c 100644 --- a/drivers/of/of_batterydata.c +++ b/drivers/of/of_batterydata.c @@ -320,7 +320,7 @@ struct device_node *of_batterydata_get_best_profile( int batt_id_kohm, const char *batt_type) { struct batt_ids batt_ids; - struct device_node *node, *best_node = NULL; + struct device_node *node, *best_node = NULL, *generic_node = NULL; const char *battery_type = NULL; int delta = 0, best_delta = 0, best_id_kohm = 0, id_range_pct, i = 0, rc = 0, limit = 0; @@ -374,10 +374,17 @@ struct device_node *of_batterydata_get_best_profile( } } } + rc = of_property_read_string(node, "qcom,battery-type", + &battery_type); + if (!rc && strcmp(battery_type, "itech_3000mah") == 0) + generic_node = node; } if (best_node == NULL) { - pr_err("No battery data found\n"); + /* now that best_node is null, there is no need to + * check whether generic node is null. */ + best_node = generic_node; + pr_err("No battery data found,use generic one\n"); return best_node; } diff --git a/drivers/pci/host/pci-msm-msi.c b/drivers/pci/host/pci-msm-msi.c index 0c6bb03471e8..7f8738eb680a 100644 --- a/drivers/pci/host/pci-msm-msi.c +++ b/drivers/pci/host/pci-msm-msi.c @@ -92,11 +92,13 @@ struct msm_msi_client { dma_addr_t msi_addr; }; -static void msm_msi_snps_handler(struct irq_desc *desc) +static bool msm_msi_snps_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct msm_msi *msi; int i; + int res; + int handled = 0; chained_irq_enter(chip, desc); @@ -121,27 +123,33 @@ static void msm_msi_snps_handler(struct irq_desc *desc) writel_relaxed(status, msi_grp->int_status_reg); for (index = 0; status; index++, status >>= 1) - if (status & 0x1) - generic_handle_irq(msi_grp->irqs[index].virq); + if (status & 0x1) { + res = generic_handle_irq( + msi_grp->irqs[index].virq); + handled += (res == 1); + } } chained_irq_exit(chip, desc); + return (handled != 0); } -static void msm_msi_qgic_handler(struct irq_desc *desc) +static bool msm_msi_qgic_handler(struct irq_desc *desc) { struct irq_chip *chip = irq_desc_get_chip(desc); struct msm_msi *msi; unsigned int virq; + int handled; chained_irq_enter(chip, desc); msi = irq_desc_get_handler_data(desc); virq = irq_find_mapping(msi->inner_domain, irq_desc_get_irq(desc)); - generic_handle_irq(virq); + handled = generic_handle_irq(virq); chained_irq_exit(chip, desc); + return (handled == 1); } static void msm_msi_snps_mask_irq(struct irq_data *data) @@ -532,7 +540,7 @@ int msm_msi_init(struct device *dev) struct device_node *of_node; const __be32 *prop_val; struct resource *res; - void (*msi_handler)(struct irq_desc *); + bool (*msi_handler)(struct irq_desc *); u32 grp; u32 index; diff --git a/drivers/pci/host/pci-msm.c b/drivers/pci/host/pci-msm.c index 9167d64c2bec..56503af5b579 100644 --- a/drivers/pci/host/pci-msm.c +++ b/drivers/pci/host/pci-msm.c @@ -6593,7 +6593,9 @@ static struct platform_driver msm_pcie_driver = { static int __init pcie_init(void) { int ret = 0, i; +#ifdef CONFIG_IPC_LOGGING char rc_name[MAX_RC_NAME_LEN]; +#endif pr_alert("pcie:%s.\n", __func__); @@ -6601,6 +6603,7 @@ static int __init pcie_init(void) mutex_init(&pcie_drv.drv_lock); for (i = 0; i < MAX_RC_NUM; i++) { +#ifdef CONFIG_IPC_LOGGING snprintf(rc_name, MAX_RC_NAME_LEN, "pcie%d-short", i); msm_pcie_dev[i].ipc_log = ipc_log_context_create(PCIE_LOG_PAGES, rc_name, 0); @@ -6631,6 +6634,7 @@ static int __init pcie_init(void) PCIE_DBG(&msm_pcie_dev[i], "PCIe IPC logging %s is enable for RC%d\n", rc_name, i); +#endif spin_lock_init(&msm_pcie_dev[i].cfg_lock); msm_pcie_dev[i].cfg_access = true; mutex_init(&msm_pcie_dev[i].enumerate_lock); diff --git a/drivers/pinctrl/qcom/pinctrl-msm.c b/drivers/pinctrl/qcom/pinctrl-msm.c index 86b139a6a647..e7fe0c732d58 100644 --- a/drivers/pinctrl/qcom/pinctrl-msm.c +++ b/drivers/pinctrl/qcom/pinctrl-msm.c @@ -621,6 +621,9 @@ static void msm_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip) unsigned i; for (i = 0; i < chip->ngpio; i++, gpio++) { + /* gpio 0~3 is NFC spi, gpio 126~129 is FP spi */ + if (i < 4 || (i > 125 && i < 130)) + continue; msm_gpio_dbg_show_one(s, NULL, chip, i, gpio); seq_puts(s, "\n"); } diff --git a/drivers/platform/msm/gsi/gsi.c b/drivers/platform/msm/gsi/gsi.c index 7714664b8a8f..6e00c7975296 100644 --- a/drivers/platform/msm/gsi/gsi.c +++ b/drivers/platform/msm/gsi/gsi.c @@ -1715,7 +1715,7 @@ int gsi_alloc_evt_ring(struct gsi_evt_ring_props *props, unsigned long dev_hdl, EXPORT_SYMBOL(gsi_alloc_evt_ring); static void __gsi_write_evt_ring_scratch(unsigned long evt_ring_hdl, - union __packed gsi_evt_scratch val) + union gsi_evt_scratch val) { gsi_writel(val.data.word1, gsi_ctx->base + GSI_EE_n_EV_CH_k_SCRATCH_0_OFFS(evt_ring_hdl, @@ -1726,7 +1726,7 @@ static void __gsi_write_evt_ring_scratch(unsigned long evt_ring_hdl, } int gsi_write_evt_ring_scratch(unsigned long evt_ring_hdl, - union __packed gsi_evt_scratch val) + union gsi_evt_scratch val) { struct gsi_evt_ctx *ctx; @@ -2472,7 +2472,7 @@ static int gsi_alloc_ap_channel(unsigned int chan_hdl) } static void __gsi_write_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch val) + union gsi_channel_scratch val) { gsi_writel(val.data.word1, gsi_ctx->base + GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(chan_hdl, @@ -2499,7 +2499,7 @@ static void __gsi_write_wdi3_channel_scratch2_reg(unsigned long chan_hdl, int gsi_write_channel_scratch3_reg(unsigned long chan_hdl, - union __packed gsi_wdi_channel_scratch3_reg val) + union gsi_wdi_channel_scratch3_reg val) { struct gsi_chan_ctx *ctx; @@ -2530,7 +2530,7 @@ int gsi_write_channel_scratch3_reg(unsigned long chan_hdl, EXPORT_SYMBOL(gsi_write_channel_scratch3_reg); static void __gsi_read_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch * val) + union gsi_channel_scratch *val) { val->data.word1 = gsi_readl(gsi_ctx->base + GSI_EE_n_GSI_CH_k_SCRATCH_0_OFFS(chan_hdl, @@ -2560,10 +2560,10 @@ static void __gsi_read_wdi3_channel_scratch2_reg(unsigned long chan_hdl, } -static union __packed gsi_channel_scratch __gsi_update_mhi_channel_scratch( - unsigned long chan_hdl, struct __packed gsi_mhi_channel_scratch mscr) +static union gsi_channel_scratch __gsi_update_mhi_channel_scratch( + unsigned long chan_hdl, struct gsi_mhi_channel_scratch mscr) { - union __packed gsi_channel_scratch scr; + union gsi_channel_scratch scr; /* below sequence is not atomic. assumption is sequencer specific fields * will remain unchanged across this sequence @@ -2620,7 +2620,7 @@ static union __packed gsi_channel_scratch __gsi_update_mhi_channel_scratch( } int gsi_write_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch val) + union gsi_channel_scratch val) { struct gsi_chan_ctx *ctx; @@ -2688,7 +2688,7 @@ EXPORT_SYMBOL(gsi_write_wdi3_channel_scratch2_reg); int gsi_read_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch *val) + union gsi_channel_scratch *val) { struct gsi_chan_ctx *ctx; @@ -2755,7 +2755,7 @@ EXPORT_SYMBOL(gsi_read_wdi3_channel_scratch2_reg); int gsi_update_mhi_channel_scratch(unsigned long chan_hdl, - struct __packed gsi_mhi_channel_scratch mscr) + struct gsi_mhi_channel_scratch mscr) { struct gsi_chan_ctx *ctx; @@ -3833,7 +3833,7 @@ int gsi_config_channel_mode(unsigned long chan_hdl, enum gsi_chan_mode mode) spin_unlock_irqrestore( &ctx->evtr->ring.slock, flags); ctx->stats.poll_pending_irq++; - GSIDBG("In IEOB WA pnd cnt = %d prvmode = %d\n", + GSIDBG("In IEOB WA pnd cnt =%lu prvmode = %d\n", ctx->stats.poll_pending_irq, chan_mode); if (chan_mode == GSI_CHAN_MODE_POLL) diff --git a/drivers/platform/msm/gsi/gsi.h b/drivers/platform/msm/gsi/gsi.h index 2b530a809c96..f0ea4976f9cf 100644 --- a/drivers/platform/msm/gsi/gsi.h +++ b/drivers/platform/msm/gsi/gsi.h @@ -150,7 +150,7 @@ struct gsi_chan_ctx { struct completion compl; bool allocated; atomic_t poll_mode; - union __packed gsi_channel_scratch scratch; + union gsi_channel_scratch scratch; struct gsi_chan_stats stats; bool enable_dp_stats; bool print_dp_stats; @@ -169,7 +169,7 @@ struct gsi_evt_ctx { struct completion compl; struct gsi_chan_ctx *chan; atomic_t chan_ref_cnt; - union __packed gsi_evt_scratch scratch; + union gsi_evt_scratch scratch; struct gsi_evt_stats stats; }; diff --git a/drivers/platform/msm/ipa/ipa_api.c b/drivers/platform/msm/ipa/ipa_api.c index 0942c97a4806..317c7da45e1a 100644 --- a/drivers/platform/msm/ipa/ipa_api.c +++ b/drivers/platform/msm/ipa/ipa_api.c @@ -2561,7 +2561,7 @@ bool ipa_has_open_aggr_frame(enum ipa_client_type client) int ipa_mhi_resume_channels_internal(enum ipa_client_type client, bool LPTransitionRejected, bool brstmode_enabled, - union __packed gsi_channel_scratch ch_scratch, u8 index) + union gsi_channel_scratch ch_scratch, u8 index) { int ret; diff --git a/drivers/platform/msm/ipa/ipa_api.h b/drivers/platform/msm/ipa/ipa_api.h index 79b41615237c..b205064af424 100644 --- a/drivers/platform/msm/ipa/ipa_api.h +++ b/drivers/platform/msm/ipa/ipa_api.h @@ -299,7 +299,7 @@ struct ipa_api_controller { enum ipa_client_type client, bool LPTransitionRejected, bool brstmode_enabled, - union __packed gsi_channel_scratch ch_scratch, + union gsi_channel_scratch ch_scratch, u8 index); int (*ipa_mhi_destroy_channel)(enum ipa_client_type client); diff --git a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c index 668b4ec7057b..beac3521c426 100644 --- a/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c +++ b/drivers/platform/msm/ipa/ipa_clients/ipa_mhi_client.c @@ -127,7 +127,7 @@ struct ipa_mhi_channel_ctx { u64 event_context_addr; struct ipa_mhi_ev_ctx ev_ctx_host; bool brstmode_enabled; - union __packed gsi_channel_scratch ch_scratch; + union gsi_channel_scratch ch_scratch; unsigned long cached_gsi_evt_ring_hdl; }; diff --git a/drivers/platform/msm/ipa/ipa_common_i.h b/drivers/platform/msm/ipa/ipa_common_i.h index 13d09af0462e..8dd838fe0aac 100644 --- a/drivers/platform/msm/ipa/ipa_common_i.h +++ b/drivers/platform/msm/ipa/ipa_common_i.h @@ -383,7 +383,7 @@ int ipa_mhi_start_channel_internal(enum ipa_client_type client); bool ipa_mhi_sps_channel_empty(enum ipa_client_type client); int ipa_mhi_resume_channels_internal(enum ipa_client_type client, bool LPTransitionRejected, bool brstmode_enabled, - union __packed gsi_channel_scratch ch_scratch, u8 index); + union gsi_channel_scratch ch_scratch, u8 index); int ipa_mhi_handle_ipa_config_req(struct ipa_config_req_msg_v01 *config_req); int ipa_mhi_query_ch_info(enum ipa_client_type client, struct gsi_chan_info *ch_info); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c index 4c7a9cce0b1c..c7f7e850bbab 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_client.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_client.c @@ -640,7 +640,7 @@ int ipa3_request_gsi_channel(struct ipa_request_gsi_channel_params *params, } memcpy(&ep->chan_scratch, ¶ms->chan_scratch, - sizeof(union __packed gsi_channel_scratch)); + sizeof(union gsi_channel_scratch)); /* * Update scratch for MCS smart prefetch: diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c index 27f4d9891b6e..69a30ac3831f 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_dp.c @@ -4486,7 +4486,7 @@ static int ipa_gsi_setup_transfer_ring(struct ipa3_ep_context *ep, u32 ring_size, struct ipa3_sys_context *user_data, gfp_t mem_flag) { dma_addr_t dma_addr; - union __packed gsi_channel_scratch ch_scratch; + union gsi_channel_scratch ch_scratch; struct gsi_chan_props gsi_channel_props; const struct ipa_gsi_ep_config *gsi_ep_info; int result; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h index c384d1ce6702..5aa74d08bd6a 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_i.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_i.h @@ -914,7 +914,7 @@ struct ipa3_ep_context { unsigned long gsi_chan_hdl; unsigned long gsi_evt_ring_hdl; struct ipa_gsi_ep_mem_info gsi_mem_info; - union __packed gsi_channel_scratch chan_scratch; + union gsi_channel_scratch chan_scratch; struct gsi_chan_xfer_notify xfer_notify; bool xfer_notify_valid; struct ipa_ep_cfg cfg; @@ -969,9 +969,9 @@ struct ipa_request_gsi_channel_params { bool skip_ep_cfg; bool keep_ipa_awake; struct gsi_evt_ring_props evt_ring_params; - union __packed gsi_evt_scratch evt_scratch; + union gsi_evt_scratch evt_scratch; struct gsi_chan_props chan_params; - union __packed gsi_channel_scratch chan_scratch; + union gsi_channel_scratch chan_scratch; }; enum ipa3_sys_pipe_policy { @@ -2704,7 +2704,7 @@ bool ipa3_has_open_aggr_frame(enum ipa_client_type client); int ipa3_mhi_resume_channels_internal(enum ipa_client_type client, bool LPTransitionRejected, bool brstmode_enabled, - union __packed gsi_channel_scratch ch_scratch, u8 index); + union gsi_channel_scratch ch_scratch, u8 index); int ipa3_mhi_destroy_channel(enum ipa_client_type client); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c index 72357d589a83..e9055fcd0f0e 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_mhi.c @@ -195,7 +195,7 @@ static int ipa_mhi_start_gsi_channel(enum ipa_client_type client, struct gsi_evt_ring_props ev_props; struct ipa_mhi_msi_info *msi; struct gsi_chan_props ch_props; - union __packed gsi_channel_scratch ch_scratch; + union gsi_channel_scratch ch_scratch; struct ipa3_ep_context *ep; const struct ipa_gsi_ep_config *ep_cfg; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; @@ -596,12 +596,12 @@ int ipa3_disconnect_mhi_pipe(u32 clnt_hdl) int ipa3_mhi_resume_channels_internal(enum ipa_client_type client, bool LPTransitionRejected, bool brstmode_enabled, - union __packed gsi_channel_scratch ch_scratch, u8 index) + union gsi_channel_scratch ch_scratch, u8 index) { int res; int ipa_ep_idx; struct ipa3_ep_context *ep; - union __packed gsi_channel_scratch gsi_ch_scratch; + union gsi_channel_scratch gsi_ch_scratch; IPA_MHI_FUNC_ENTRY(); diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c index 4db29847616c..c1cae3cf4dbb 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.c @@ -786,6 +786,39 @@ int ipa3_qmi_filter_request_send(struct ipa_install_fltr_rule_req_msg_v01 *req) resp.resp.error, "ipa_install_filter"); } +static int ipa3_qmi_filter_request_ex_calc_length( + struct ipa_install_fltr_rule_req_ex_msg_v01 *req) +{ + int len = 0; + + /* + * caller should validate and send the req instead of sending max + * length, the approximate length is calculated + */ + len += ((sizeof(struct ipa_install_fltr_rule_req_ex_msg_v01)) - + (QMI_IPA_MAX_FILTERS_EX_V01 * + sizeof(struct ipa_filter_spec_ex_type_v01) - + QMI_IPA_MAX_FILTERS_EX_V01 * sizeof(uint32_t)) - + (QMI_IPA_MAX_FILTERS_V01 * + sizeof(struct ipa_filter_spec_ex2_type_v01))); + + if(req->filter_spec_ex_list_valid && + req->filter_spec_ex_list_len > 0) + len += sizeof(struct ipa_filter_spec_ex_type_v01)* + req->filter_spec_ex_list_len; + + if( req->xlat_filter_indices_list_valid && + req->xlat_filter_indices_list_len > 0) + len += sizeof(uint32_t)*req->xlat_filter_indices_list_len; + + if(req->filter_spec_ex2_list_valid && + req->filter_spec_ex2_list_len > 0 ) + len += sizeof(struct ipa_filter_spec_ex2_type_v01)* + req->filter_spec_ex2_list_len; + + return len; +} + /* sending filter-install-request to modem*/ int ipa3_qmi_filter_request_ex_send( struct ipa_install_fltr_rule_req_ex_msg_v01 *req) @@ -851,8 +884,9 @@ int ipa3_qmi_filter_request_ex_send( } mutex_unlock(&ipa3_qmi_lock); - req_desc.max_msg_len = - QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_MAX_MSG_LEN_V01; + req_desc.max_msg_len = ipa3_qmi_filter_request_ex_calc_length(req); + IPAWANDBG("QMI send request length = %d\n", req_desc.max_msg_len); + req_desc.msg_id = QMI_IPA_INSTALL_FILTER_RULE_EX_REQ_V01; req_desc.ei_array = ipa3_install_fltr_rule_req_ex_msg_data_v01_ei; @@ -1347,25 +1381,13 @@ int ipa3_qmi_filter_notify_send( return -EINVAL; } - if (req->rule_id_ex_len == 0) { - IPAWANDBG(" delete UL filter rule for pipe %d\n", - req->source_pipe_index); - } else if (req->rule_id_ex_len > QMI_IPA_MAX_FILTERS_EX2_V01) { - IPAWANERR(" UL filter rule for pipe %d exceed max (%u)\n", - req->source_pipe_index, - req->rule_id_ex_len); - return -EINVAL; - } - if (req->install_status != IPA_QMI_RESULT_SUCCESS_V01) { IPAWANERR(" UL filter rule for pipe %d install_status = %d\n", req->source_pipe_index, req->install_status); return -EINVAL; - } else if ((req->rule_id_valid != 1) && - (req->rule_id_ex_valid != 1)) { - IPAWANERR(" UL filter rule for pipe %d rule_id_valid = %d/%d\n", - req->source_pipe_index, req->rule_id_valid, - req->rule_id_ex_valid); + } else if (req->rule_id_valid != 1) { + IPAWANERR(" UL filter rule for pipe %d rule_id_valid = %d\n", + req->source_pipe_index, req->rule_id_valid); return -EINVAL; } else if (req->source_pipe_index >= ipa3_ctx->ipa_num_pipes) { IPAWANDBG( @@ -1700,14 +1722,6 @@ static struct qmi_msg_handler server_handlers[] = { struct ipa_init_modem_driver_cmplt_req_msg_v01), .fn = ipa3_handle_modem_init_cmplt_req, }, - { - .type = QMI_REQUEST, - .msg_id = QMI_IPA_INIT_MODEM_DRIVER_CMPLT_REQ_V01, - .ei = ipa3_init_modem_driver_cmplt_req_msg_data_v01_ei, - .decoded_size = sizeof( - struct ipa_init_modem_driver_cmplt_req_msg_v01), - .fn = ipa3_handle_modem_init_cmplt_req, - }, { .type = QMI_REQUEST, .msg_id = QMI_IPA_MHI_ALLOC_CHANNEL_REQ_V01, diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h index dae6a6c6c37c..fdac0b673989 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service.h @@ -116,9 +116,6 @@ struct ipa3_qmi_context { int num_ipa_offload_connection; struct ipa_offload_connection_val ipa_offload_cache[QMI_IPA_MAX_FILTERS_V01]; - uint8_t ul_firewall_indices_list_valid; - uint32_t ul_firewall_indices_list_len; - uint32_t ul_firewall_indices_list[QMI_IPA_MAX_FILTERS_V01]; }; struct ipa3_rmnet_mux_val { diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c index 57bb0552f2d9..8b5be00a1b48 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_qmi_service_v01.c @@ -2324,7 +2324,7 @@ struct qmi_elem_info ipa3_fltr_installed_notif_req_msg_data_v01_ei[] = { { .data_type = QMI_DATA_LEN, .elem_len = 1, - .elem_size = sizeof(uint32_t), + .elem_size = sizeof(uint8_t), .is_array = NO_ARRAY, .tlv_type = 0x19, .offset = offsetof( diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c index 3705251de416..46f1fdce463d 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_uc_wdi.c @@ -1059,7 +1059,7 @@ static int ipa3_wdi2_gsi_alloc_evt_ring( enum ipa_client_type client, unsigned long *evt_ring_hdl) { - union __packed gsi_evt_scratch evt_scratch; + union gsi_evt_scratch evt_scratch; int result = -EFAULT; /* GSI EVENT RING allocation */ @@ -1178,7 +1178,7 @@ int ipa3_connect_gsi_wdi_pipe(struct ipa_wdi_in_params *in, struct ipa_ep_cfg_ctrl ep_cfg_ctrl; struct gsi_chan_props gsi_channel_props; struct gsi_evt_ring_props gsi_evt_ring_props; - union __packed gsi_channel_scratch gsi_scratch; + union gsi_channel_scratch gsi_scratch; phys_addr_t pa; unsigned long va; u32 gsi_db_reg_phs_addr_lsb; @@ -2453,7 +2453,7 @@ int ipa3_resume_gsi_wdi_pipe(u32 clnt_hdl) struct ipa3_ep_context *ep; struct ipa_ep_cfg_ctrl ep_cfg_ctrl; struct gsi_chan_info chan_info; - union __packed gsi_channel_scratch gsi_scratch; + union gsi_channel_scratch gsi_scratch; struct IpaHwOffloadStatsAllocCmdData_t *pcmd_t = NULL; IPADBG("ep=%d\n", clnt_hdl); @@ -2590,7 +2590,7 @@ int ipa3_suspend_gsi_wdi_pipe(u32 clnt_hdl) struct ipahal_ep_cfg_ctrl_scnd ep_ctrl_scnd = { 0 }; int retry_cnt = 0; struct gsi_chan_info chan_info; - union __packed gsi_channel_scratch gsi_scratch; + union gsi_channel_scratch gsi_scratch; struct IpaHwOffloadStatsAllocCmdData_t *pcmd_t = NULL; ipa_ep_idx = ipa3_get_ep_mapping(ipa3_get_client_mapping(clnt_hdl)); @@ -2833,7 +2833,7 @@ int ipa3_write_qmapid_gsi_wdi_pipe(u32 clnt_hdl, u8 qmap_id) { int result = 0; struct ipa3_ep_context *ep; - union __packed gsi_wdi_channel_scratch3_reg gsi_scratch; + union gsi_wdi_channel_scratch3_reg gsi_scratch; memset(&gsi_scratch, 0, sizeof(gsi_scratch)); ep = &ipa3_ctx->ep[clnt_hdl]; diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c index 17a9dcf8a922..22b353e7e8c0 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wdi3_i.c @@ -75,8 +75,8 @@ static int ipa3_setup_wdi3_gsi_channel(u8 is_smmu_enabled, { struct gsi_evt_ring_props gsi_evt_ring_props; struct gsi_chan_props gsi_channel_props; - union __packed gsi_channel_scratch ch_scratch; - union __packed gsi_evt_scratch evt_scratch; + union gsi_channel_scratch ch_scratch; + union gsi_evt_scratch evt_scratch; const struct ipa_gsi_ep_config *gsi_ep_info; int result, len; unsigned long va; @@ -887,7 +887,7 @@ int ipa3_write_qmapid_wdi3_gsi_pipe(u32 clnt_hdl, u8 qmap_id) { int result = 0; struct ipa3_ep_context *ep; - union __packed gsi_wdi3_channel_scratch2_reg scratch2_reg; + union gsi_wdi3_channel_scratch2_reg scratch2_reg; memset(&scratch2_reg, 0, sizeof(scratch2_reg)); if (clnt_hdl >= ipa3_ctx->ipa_num_pipes || diff --git a/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c b/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c index 8b8b8c856946..00c2424353d7 100644 --- a/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c +++ b/drivers/platform/msm/ipa/ipa_v3/ipa_wigig_i.c @@ -394,7 +394,7 @@ static int ipa3_wigig_config_gsi(bool Rx, { struct gsi_evt_ring_props evt_props; struct gsi_chan_props channel_props; - union __packed gsi_channel_scratch gsi_scratch; + union gsi_channel_scratch gsi_scratch; int gsi_res; struct ipa_wigig_pipe_setup_info_smmu *pipe_smmu; struct ipa_wigig_pipe_setup_info *pipe; @@ -441,7 +441,7 @@ static int ipa3_wigig_config_gsi(bool Rx, /* event scratch not configured by SW for TX channels */ if (Rx) { - union __packed gsi_evt_scratch evt_scratch; + union gsi_evt_scratch evt_scratch; memset(&evt_scratch, 0, sizeof(evt_scratch)); evt_scratch.w11ad.update_status_hwtail_mod_threshold = 1; diff --git a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c index d78a9a0f8fdc..4821bcfb06f5 100644 --- a/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c +++ b/drivers/platform/msm/ipa/ipa_v3/rmnet_ipa.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2020, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -691,41 +691,6 @@ int ipa3_copy_ul_filter_rule_to_ipa(struct ipa_install_fltr_rule_req_msg_v01 } } } - - if (rule_req->ul_firewall_indices_list_valid) { - IPAWANDBG("Receive ul_firewall_indices_list_len = (%d)", - rule_req->ul_firewall_indices_list_len); - - if (rule_req->ul_firewall_indices_list_len > - rmnet_ipa3_ctx->num_q6_rules) { - IPAWANERR("UL rule indices are not valid: (%d/%d)\n", - rule_req->xlat_filter_indices_list_len, - rmnet_ipa3_ctx->num_q6_rules); - goto failure; - } - - ipa3_qmi_ctx->ul_firewall_indices_list_valid = 1; - ipa3_qmi_ctx->ul_firewall_indices_list_len = - rule_req->ul_firewall_indices_list_len; - - for (i = 0; i < rule_req->ul_firewall_indices_list_len; i++) { - ipa3_qmi_ctx->ul_firewall_indices_list[i] = - rule_req->ul_firewall_indices_list[i]; - } - - for (i = 0; i < rule_req->ul_firewall_indices_list_len; i++) { - if (rule_req->ul_firewall_indices_list[i] - >= rmnet_ipa3_ctx->num_q6_rules) { - IPAWANERR("UL rule idx is wrong: %d\n", - rule_req->ul_firewall_indices_list[i]); - goto failure; - } else { - ipa3_qmi_ctx->q6_ul_filter_rule - [rule_req->ul_firewall_indices_list[i]] - .replicate_needed = 1; - } - } - } goto success; failure: @@ -2125,7 +2090,7 @@ static void ipa3_wwan_setup(struct net_device *dev) dev->flags &= ~(IFF_BROADCAST | IFF_MULTICAST); dev->needed_headroom = HEADROOM_FOR_QMAP; dev->needed_tailroom = TAILROOM; - dev->watchdog_timeo = 1000; + dev->watchdog_timeo = 5000; } /* IPA_RM related functions start*/ diff --git a/drivers/platform/msm/sps/sps.c b/drivers/platform/msm/sps/sps.c index c9bb3e7586e2..3a132f06c49a 100644 --- a/drivers/platform/msm/sps/sps.c +++ b/drivers/platform/msm/sps/sps.c @@ -2106,7 +2106,9 @@ int sps_register_bam_device(const struct sps_bam_props *bam_props, { struct sps_bam *bam = NULL; void __iomem *virt_addr = NULL; +#ifdef CONFIG_IPC_LOGGING char bam_name[MAX_MSG_LEN]; +#endif u32 manage; int ok; int result; @@ -2200,6 +2202,7 @@ int sps_register_bam_device(const struct sps_bam_props *bam_props, if (virt_addr != NULL) bam->props.virt_addr = virt_addr; +#ifdef CONFIG_IPC_LOGGING snprintf(bam_name, sizeof(bam_name), "sps_bam_%pa_0", &bam->props.phys_addr); bam->ipc_log0 = ipc_log_context_create(SPS_IPC_LOGPAGES, @@ -2239,6 +2242,7 @@ int sps_register_bam_device(const struct sps_bam_props *bam_props, if (!bam->ipc_log4) SPS_ERR(sps, "%s : unable to create IPC Logging 4 for bam %pa", __func__, &bam->props.phys_addr); +#endif if (bam_props->ipc_loglevel) bam->ipc_loglevel = bam_props->ipc_loglevel; @@ -2346,11 +2350,13 @@ int sps_deregister_bam_device(unsigned long dev_handle) mutex_lock(&bam->lock); sps_bam_device_de_init(bam); mutex_unlock(&bam->lock); +#ifdef CONFIG_IPC_LOGGING ipc_log_context_destroy(bam->ipc_log0); ipc_log_context_destroy(bam->ipc_log1); ipc_log_context_destroy(bam->ipc_log2); ipc_log_context_destroy(bam->ipc_log3); ipc_log_context_destroy(bam->ipc_log4); +#endif if (bam->props.virt_size) (void)iounmap(bam->props.virt_addr); @@ -3039,6 +3045,7 @@ static int __init sps_init(void) if (sps == NULL) return -ENOMEM; +#ifdef CONFIG_IPC_LOGGING sps->ipc_log0 = ipc_log_context_create(SPS_IPC_LOGPAGES, "sps_ipc_log0", 0); if (!sps->ipc_log0) @@ -3059,6 +3066,7 @@ static int __init sps_init(void) SPS_IPC_REG_DUMP_FACTOR, "sps_ipc_log4", 0); if (!sps->ipc_log4) pr_err("Failed to create IPC log4\n"); +#endif ret = platform_driver_register(&msm_sps_driver); diff --git a/drivers/power/reset/msm-poweroff.c b/drivers/power/reset/msm-poweroff.c index ba361d73c8f3..4147e990a6ac 100644 --- a/drivers/power/reset/msm-poweroff.c +++ b/drivers/power/reset/msm-poweroff.c @@ -305,7 +305,9 @@ static void msm_restart_prepare(const char *cmd) else qpnp_pon_system_pwr_off(PON_POWER_OFF_HARD_RESET); - if (cmd != NULL) { + if (in_panic) { + qpnp_pon_set_restart_reason(PON_RESTART_REASON_PANIC); + } else if (cmd != NULL) { if (!strncmp(cmd, "bootloader", 10)) { qpnp_pon_set_restart_reason( PON_RESTART_REASON_BOOTLOADER); @@ -341,8 +343,12 @@ static void msm_restart_prepare(const char *cmd) } else if (!strncmp(cmd, "edl", 3)) { enable_emergency_dload_mode(); } else { + qpnp_pon_set_restart_reason(PON_RESTART_REASON_NORMAL); __raw_writel(0x77665501, restart_reason); } + } else { + qpnp_pon_set_restart_reason(PON_RESTART_REASON_NORMAL); + __raw_writel(0x77665501, restart_reason); } flush_cache_all(); diff --git a/drivers/power/supply/power_supply_core.c b/drivers/power/supply/power_supply_core.c index 52a776b85d3e..c0ecc0187e80 100644 --- a/drivers/power/supply/power_supply_core.c +++ b/drivers/power/supply/power_supply_core.c @@ -354,7 +354,7 @@ static int __power_supply_is_system_supplied(struct device *dev, void *data) unsigned int *count = data; (*count)++; - if (psy->desc->type != POWER_SUPPLY_TYPE_BATTERY) + if ((psy->desc->type != POWER_SUPPLY_TYPE_BATTERY) && (psy->desc->type != POWER_SUPPLY_TYPE_BMS)) if (!psy->desc->get_property(psy, POWER_SUPPLY_PROP_ONLINE, &ret)) return ret.intval; diff --git a/drivers/power/supply/power_supply_leds.c b/drivers/power/supply/power_supply_leds.c index 2277ad9c2f68..af2f76f8b2db 100644 --- a/drivers/power/supply/power_supply_leds.c +++ b/drivers/power/supply/power_supply_leds.c @@ -113,6 +113,8 @@ static void power_supply_remove_bat_triggers(struct power_supply *psy) static void power_supply_update_gen_leds(struct power_supply *psy) { + /* xiaomi project don't support this feature, return skip this feature*/ + #if 0 union power_supply_propval online; if (power_supply_get_property(psy, POWER_SUPPLY_PROP_ONLINE, &online)) @@ -124,6 +126,7 @@ static void power_supply_update_gen_leds(struct power_supply *psy) led_trigger_event(psy->online_trig, LED_FULL); else led_trigger_event(psy->online_trig, LED_OFF); + #endif } static int power_supply_create_gen_triggers(struct power_supply *psy) diff --git a/drivers/power/supply/power_supply_sysfs.c b/drivers/power/supply/power_supply_sysfs.c index 01c3e6566702..4ae974af0d76 100644 --- a/drivers/power/supply/power_supply_sysfs.c +++ b/drivers/power/supply/power_supply_sysfs.c @@ -46,7 +46,7 @@ static const char * const power_supply_type_text[] = { "USB_PD", "USB_PD_DRP", "BrickID", "USB_HVDCP", "USB_HVDCP_3", "USB_HVDCP_3P5", "Wireless", "USB_FLOAT", "BMS", "Parallel", "Main", "Wipower", "USB_C_UFP", "USB_C_DFP", - "Charge_Pump", + "Charge_Pump","ZIMI_CAR_POWER" }; static const char * const power_supply_status_text[] = { @@ -163,6 +163,21 @@ static ssize_t power_supply_show_property(struct device *dev, if (off == POWER_SUPPLY_PROP_CHARGE_COUNTER_EXT) return sprintf(buf, "%lld\n", value.int64val); + else if (off == POWER_SUPPLY_PROP_WIRELESS_VERSION) + return scnprintf(buf, PAGE_SIZE, "0x%x\n", + value.intval); + else if (off == POWER_SUPPLY_PROP_WIRELESS_WAKELOCK) + return scnprintf(buf, PAGE_SIZE, "%d\n", + value.intval); + else if (off == POWER_SUPPLY_PROP_SIGNAL_STRENGTH) + return scnprintf(buf, PAGE_SIZE, "%d\n", + value.intval); + else if (off == POWER_SUPPLY_PROP_WIRELESS_CP_EN) + return scnprintf(buf, PAGE_SIZE, "%d\n", + value.intval); + else if (off == POWER_SUPPLY_PROP_TYPE_RECHECK) + return scnprintf(buf, PAGE_SIZE, "0x%x\n", + value.intval); else return sprintf(buf, "%d\n", value.intval); } @@ -294,6 +309,8 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(charge_enabled), POWER_SUPPLY_ATTR(set_ship_mode), POWER_SUPPLY_ATTR(real_type), + POWER_SUPPLY_ATTR(hvdcp3_type), + POWER_SUPPLY_ATTR(quick_charge_type), POWER_SUPPLY_ATTR(charge_now_raw), POWER_SUPPLY_ATTR(charge_now_error), POWER_SUPPLY_ATTR(capacity_raw), @@ -348,6 +365,7 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(typec_src_rp), POWER_SUPPLY_ATTR(pd_allowed), POWER_SUPPLY_ATTR(pd_active), + POWER_SUPPLY_ATTR(pd_authentication), POWER_SUPPLY_ATTR(pd_in_hard_reset), POWER_SUPPLY_ATTR(pd_current_max), POWER_SUPPLY_ATTR(pd_usb_suspend_supported), @@ -371,9 +389,16 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(pd_voltage_max), POWER_SUPPLY_ATTR(pd_voltage_min), POWER_SUPPLY_ATTR(sdp_current_max), + POWER_SUPPLY_ATTR(dc_thermal_levels), POWER_SUPPLY_ATTR(connector_type), POWER_SUPPLY_ATTR(parallel_batfet_mode), POWER_SUPPLY_ATTR(parallel_fcc_max), + POWER_SUPPLY_ATTR(wireless_version), + POWER_SUPPLY_ATTR(signal_strength), + POWER_SUPPLY_ATTR(wireless_cp_en), + POWER_SUPPLY_ATTR(wireless_power_good_en), + POWER_SUPPLY_ATTR(wireless_wakelock), + POWER_SUPPLY_ATTR(tx_adapter), POWER_SUPPLY_ATTR(min_icl), POWER_SUPPLY_ATTR(moisture_detected), POWER_SUPPLY_ATTR(batt_profile_version), @@ -389,6 +414,9 @@ static struct device_attribute power_supply_attrs[] = { POWER_SUPPLY_ATTR(force_recharge), POWER_SUPPLY_ATTR(fcc_stepper_enable), POWER_SUPPLY_ATTR(toggle_stat), + POWER_SUPPLY_ATTR(type_recheck), + POWER_SUPPLY_ATTR(liquid_detection), + POWER_SUPPLY_ATTR(dynamic_fv_enabled), POWER_SUPPLY_ATTR(main_fcc_max), POWER_SUPPLY_ATTR(fg_reset), POWER_SUPPLY_ATTR(qc_opti_disable), diff --git a/drivers/power/supply/qcom/Kconfig b/drivers/power/supply/qcom/Kconfig index 04a1fde9d741..bd864f421568 100644 --- a/drivers/power/supply/qcom/Kconfig +++ b/drivers/power/supply/qcom/Kconfig @@ -48,6 +48,17 @@ config SMB1355_SLAVE_CHARGER The driver reports the charger status via the power supply framework. A charger status change triggers an IRQ via the device STAT pin. +config IDT_P9220 + tristate "idtp9220 wireless Charger" + depends on I2C + help + Say Y to include support for idtp9220 wireless Charger. + idtp9220 is a wireless battery charger. + The driver supports charger enable/disable. + The driver reports the charger status via the power supply framework. + The driver controls idtp9220 via I2C and + supports device-tree interface. + config QPNP_SMB2 tristate "SMB2 Battery Charger" depends on MFD_SPMI_PMIC diff --git a/drivers/power/supply/qcom/Makefile b/drivers/power/supply/qcom/Makefile index 2d116c9adb49..855c0089b877 100644 --- a/drivers/power/supply/qcom/Makefile +++ b/drivers/power/supply/qcom/Makefile @@ -9,5 +9,6 @@ obj-$(CONFIG_QPNP_QNOVO) += qpnp-qnovo.o battery.o obj-$(CONFIG_QPNP_QNOVO5) += qpnp-qnovo5.o battery.o obj-$(CONFIG_QPNP_SMB5) += step-chg-jeita.o battery.o qpnp-smb5.o smb5-lib.o pmic-voter.o storm-watch.o schgm-flash.o obj-$(CONFIG_SMB1390_CHARGE_PUMP) += smb1390-charger.o pmic-voter.o +obj-$(CONFIG_IDT_P9220) += idtp9220.o obj-$(CONFIG_SMB1390_CHARGE_PUMP_PSY) += smb1390-charger-psy.o pmic-voter.o obj-$(CONFIG_SMB1398_CHARGER) += smb1398-charger.o pmic-voter.o diff --git a/drivers/power/supply/qcom/battery.c b/drivers/power/supply/qcom/battery.c index 5d99458399e1..f7dab972ae2e 100644 --- a/drivers/power/supply/qcom/battery.c +++ b/drivers/power/supply/qcom/battery.c @@ -1,4 +1,5 @@ /* Copyright (c) 2017-2020 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -1306,11 +1307,34 @@ static int usb_icl_vote_callback(struct votable *votable, void *data, vote(chip->pl_disable_votable, ICL_CHANGE_VOTER, false, 0); + if (!chip->usb_psy) + chip->usb_psy = power_supply_get_by_name("usb"); + if (!chip->usb_psy) { + pr_err("Couldn't get usb psy\n"); + return -ENODEV; + } + + rc = power_supply_get_property(chip->usb_psy, + POWER_SUPPLY_PROP_SMB_EN_REASON, &pval); + if (rc < 0) { + pr_err("Couldn't get cp reason rc=%d\n", rc); + return rc; + } + + if (chip->cp_ilim_votable) { + if (pval.intval != POWER_SUPPLY_CP_WIRELESS) + vote(chip->cp_ilim_votable, ICL_CHANGE_VOTER, true, icl_ua); + else + vote(chip->cp_ilim_votable, ICL_CHANGE_VOTER, false, 0); + } + /* Configure ILIM based on AICL result only if input mode is USBMID */ if (cp_get_parallel_mode(chip, PARALLEL_INPUT_MODE) == POWER_SUPPLY_PL_USBMID_USBMID) cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua); + cp_configure_ilim(chip, ICL_CHANGE_VOTER, icl_ua); + return 0; } diff --git a/drivers/power/supply/qcom/fg-alg.c b/drivers/power/supply/qcom/fg-alg.c index c27f1d481cf3..9d6b1488d5ab 100644 --- a/drivers/power/supply/qcom/fg-alg.c +++ b/drivers/power/supply/qcom/fg-alg.c @@ -1,4 +1,5 @@ /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -277,7 +278,28 @@ int get_cycle_counts(struct cycle_counter *counter, const char **buf) return 0; } -/** + /** + * set_cycle_count - + * @counter: Cycle counter object + * @value: The cycle count value to be set + * + * Get average cycle count for all buckets + * + */ +int set_cycle_count(struct cycle_counter *counter, u16 count) +{ + int rc, id; + + for (id = 0; id < BUCKET_COUNT; id++) { + rc = counter->store_count(counter->data, &count, id, 2); + if (rc < 0) + pr_err("failed to clear cycle counter rc=%d\n", rc); + } + + return 0; +} + + /** * cycle_count_init - * @counter: Cycle counter object * diff --git a/drivers/power/supply/qcom/fg-alg.h b/drivers/power/supply/qcom/fg-alg.h index 86e9be88f2da..7e68539fa6f2 100644 --- a/drivers/power/supply/qcom/fg-alg.h +++ b/drivers/power/supply/qcom/fg-alg.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -156,6 +157,7 @@ void cycle_count_update(struct cycle_counter *counter, int batt_soc, int charge_status, bool charge_done, bool input_present); int get_cycle_count(struct cycle_counter *counter, int *count); int get_cycle_counts(struct cycle_counter *counter, const char **buf); +int set_cycle_count(struct cycle_counter *counter, u16 count); int cycle_count_init(struct cycle_counter *counter); void cap_learning_abort(struct cap_learning *cl); void cap_learning_update(struct cap_learning *cl, int batt_temp, diff --git a/drivers/power/supply/qcom/fg-core.h b/drivers/power/supply/qcom/fg-core.h index f128b38bc8a0..3f8fcb8c080e 100644 --- a/drivers/power/supply/qcom/fg-core.h +++ b/drivers/power/supply/qcom/fg-core.h @@ -1,4 +1,5 @@ /* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -88,12 +89,22 @@ #define FULL_CAPACITY 100 #define FULL_SOC_RAW 255 +#define FULL_SOC_REPORT_THR 250 #define DEBUG_BATT_SOC 67 #define BATT_MISS_SOC 50 #define ESR_SOH_SOC 50 #define EMPTY_SOC 0 +#define VBAT_RESTART_FG_EMPTY_UV 3700000 +#define TEMP_THR_RESTART_FG 150 +#define RESTART_FG_START_WORK_MS 1000 +#define RESTART_FG_WORK_MS 2000 +#define EMPTY_REPORT_SOC 1 + +#define VBAT_CRITICAL_LOW_THR 2800 +#define EMPTY_DEBOUNCE_TIME_COUNT_MAX 5 + enum prof_load_status { PROFILE_MISSING, PROFILE_LOADED, @@ -311,6 +322,7 @@ struct fg_batt_props { int float_volt_uv; int vbatt_full_mv; int fastchg_curr_ma; + int nom_cap_uah; int *therm_coeffs; int therm_ctr_offset; int therm_pull_up_kohms; @@ -450,6 +462,8 @@ struct fg_dev { int delta_soc; int last_msoc; int last_recharge_volt_mv; + int vbatt_full_volt_uv; + int vbat_critical_low_count; bool profile_available; enum prof_load_status profile_load_status; bool battery_missing; @@ -458,14 +472,19 @@ struct fg_dev { bool recharge_soc_adjusted; bool soc_reporting_ready; bool use_ima_single_mode; + bool report_full; bool use_dma; bool qnovo_enable; + bool empty_restart_fg; + bool input_present; enum fg_version version; struct completion soc_update; struct completion soc_ready; struct delayed_work profile_load_work; struct work_struct status_change_work; struct delayed_work sram_dump_work; + struct delayed_work empty_restart_fg_work; + struct delayed_work soc_work; }; /* Debugfs data structures are below */ diff --git a/drivers/power/supply/qcom/fg-util.c b/drivers/power/supply/qcom/fg-util.c index c697e13cfa47..548b4666fcd9 100644 --- a/drivers/power/supply/qcom/fg-util.c +++ b/drivers/power/supply/qcom/fg-util.c @@ -1,4 +1,5 @@ /* Copyright (c) 2016-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -390,7 +391,7 @@ void fg_notify_charger(struct fg_dev *fg) } } - if (fg->bp.fastchg_curr_ma > 0) { + /*if (fg->bp.fastchg_curr_ma > 0) { prop.intval = fg->bp.fastchg_curr_ma * 1000; rc = power_supply_set_property(fg->batt_psy, POWER_SUPPLY_PROP_CONSTANT_CHARGE_CURRENT_MAX, @@ -400,7 +401,7 @@ void fg_notify_charger(struct fg_dev *fg) rc); return; } - } + }*/ } bool batt_psy_initialized(struct fg_dev *fg) @@ -850,6 +851,8 @@ int fg_restart(struct fg_dev *fg, int wait_time_ms) goto out; } out: + if (fg->empty_restart_fg) + fg->empty_restart_fg = false; fg->fg_restarting = false; return rc; } @@ -899,10 +902,17 @@ int fg_get_msoc(struct fg_dev *fg, int *msoc) * of the values 1-254 will be scaled to 1-99. DIV_ROUND_UP will not * be suitable here as it rounds up any value higher than 252 to 100. */ - if (*msoc == FULL_SOC_RAW) + if ((*msoc >= FULL_SOC_REPORT_THR - 2) + && (*msoc < FULL_SOC_RAW) && fg->report_full) { + *msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW) + 1; + if (*msoc >= FULL_CAPACITY) + *msoc = FULL_CAPACITY; + } else if (*msoc == FULL_SOC_RAW) *msoc = 100; else if (*msoc == 0) *msoc = 0; + else if (*msoc >= FULL_SOC_REPORT_THR - 4 && *msoc <= FULL_SOC_REPORT_THR - 3 && fg->report_full) + *msoc = DIV_ROUND_CLOSEST(*msoc * FULL_CAPACITY, FULL_SOC_RAW); else *msoc = DIV_ROUND_CLOSEST((*msoc - 1) * (FULL_CAPACITY - 2), FULL_SOC_RAW - 2) + 1; diff --git a/drivers/power/supply/qcom/idtp9220.c b/drivers/power/supply/qcom/idtp9220.c new file mode 100644 index 000000000000..53b4dd4656e9 --- /dev/null +++ b/drivers/power/supply/qcom/idtp9220.c @@ -0,0 +1,2201 @@ +/** + * Copyright “Copyright (C) 2018 XiaoMi, Inc + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +/*add for sdm845 request*/ +#include +#include +#include +#include +#include +#include +#include +#include + +/* +#ifdef CONFIG_DRM +#include +#endif +*/ + +static struct idtp9220_device_info *g_di; + +struct idtp9220_access_func { + int (*read)(struct idtp9220_device_info *di, u16 reg, u8 *val); + int (*write)(struct idtp9220_device_info *di, u16 reg, u8 val); + int (*read_buf)(struct idtp9220_device_info *di, + u16 reg, u8 *buf, u32 size); + int (*write_buf)(struct idtp9220_device_info *di, + u16 reg, u8 *buf, u32 size); +}; + +struct idtp9220_dt_props { + unsigned int irq_gpio; + unsigned int enable_gpio; + unsigned int wpc_det_gpio; +}; + +struct idtp9220_device_info { + int chip_enable; + char *name; + struct device *dev; + struct idtp9220_access_func bus; + struct regmap *regmap; + struct idtp9220_dt_props dt_props; + int irq; + int wpc_irq; + struct delayed_work irq_work; + struct delayed_work wpc_det_work; + struct pinctrl *idt_pinctrl; + struct pinctrl_state *idt_gpio_active; + struct pinctrl_state *idt_gpio_suspend; + struct power_supply *usb_psy; + struct power_supply *dc_psy; + struct power_supply *batt_psy; + struct power_supply *idtp_psy; + struct power_supply *wireless_psy; + struct mutex read_lock; + struct mutex write_lock; + struct delayed_work chg_monitor_work; + struct delayed_work chg_detect_work; + struct delayed_work bpp_connect_load_work; + struct delayed_work epp_connect_load_work; + struct delayed_work cmd_check_work; + struct delayed_work vout_regulator_work; + struct delayed_work rx_vout_work; + struct delayed_work dc_check_work; + struct delayed_work fast_operate_work; + struct delayed_work mophie_tx_work; + struct delayed_work bpp_e5_tx_work; + struct delayed_work qc2_f1_tx_work; + struct delayed_work qc3_epp_work; + + bool screen_on; + int tx_charger_type; + int status; + int count_5v; + int count_9v; + int count_12v; + int count_15v; + int exchange; + int epp_exchange; + int dcin_present; + int epp; + int vbuck; + int power_off_mode; + int power_max; + u8 header; + u8 cmd; + int is_compatible_hwid; + int last_vin; + int last_vbuck; + int is_car_tx; + int last_icl; + int power_good_flag; + + /*idt9220 charging info*/ + int vout; + int iout; + int f; + int vrect; + int ss; + int is_vin_limit; + int is_epp_qc3; + /* bpp e5_tx info*/ + int last_bpp_icl; + int last_bpp_vout; + /* qc2+f1_tx info*/ + int is_f1_tx; + int bpp_vout_rise; + int last_qc2_vout; + int last_qc2_icl; + /* qc3_epp+f1_tx info*/ + int last_qc3_vout; + int last_qc3_icl; +}; + +void idtp922x_request_adapter(struct idtp9220_device_info *di); +static void idtp9220_set_charging_param(struct idtp9220_device_info *di); + +/*static int idt_signal_strength = 0; +module_param_named(ss, idt_signal_strength, int, 0600); +*/ + +static int idt_signal_range = 2; +module_param_named(signal_range, idt_signal_range, int, 0644); + +static int idtp9220_get_property_names(struct idtp9220_device_info *di) +{ + di->batt_psy = power_supply_get_by_name("battery"); + if (!di->batt_psy) { + dev_err(di->dev, "[idt] no batt_psy,return\n"); + return -EINVAL; + } + di->dc_psy = power_supply_get_by_name("dc"); + if (!di->dc_psy) { + dev_err(di->dev, "[idt] no dc_psy,return\n"); + return -EINVAL; + } + di->usb_psy = power_supply_get_by_name("usb"); + if (!di->usb_psy) { + dev_err(di->dev, "[idt] no usb_psy,return\n"); + return -EINVAL; + } + di->wireless_psy = power_supply_get_by_name("wireless"); + if (!di->wireless_psy) { + dev_err(di->dev, "[idt] no wireless_psy,return\n"); + return -EINVAL; + } + return 0; +} + + +int idtp9220_read(struct idtp9220_device_info *di, u16 reg, u8 *val) { + unsigned int temp; + int rc; + + mutex_lock(&di->read_lock); + rc = regmap_read(di->regmap, reg, &temp); + if (rc >= 0) + *val = (u8)temp; + + mutex_unlock(&di->read_lock); + return rc; +} + +int idtp9220_write(struct idtp9220_device_info *di, u16 reg, u8 val) { + int rc = 0; + + mutex_lock(&di->write_lock); + rc = regmap_write(di->regmap, reg, val); + if (rc < 0) + dev_err(di->dev, "[idt] idtp9220 write error: %d\n", rc); + + mutex_unlock(&di->write_lock); + return rc; +} + +int idtp9220_read_buffer(struct idtp9220_device_info *di, u16 reg, u8 *buf, u32 size) { + int rc =0; + + while (size--) { + rc = di->bus.read(di, reg++, buf++); + if (rc < 0) { + dev_err(di->dev, "[idt] write error: %d\n", rc); + return rc; + } + } + + return rc; +} + +int idtp9220_write_buffer(struct idtp9220_device_info *di, u16 reg, u8 *buf, u32 size) { + int rc = 0; + + while (size--) { + rc = di->bus.write(di, reg++, *buf++); + if (rc < 0) { + dev_err(di->dev, "[idt] write error: %d\n", rc); + return rc; + } + } + + return rc; +} + +u32 ExtractPacketSize(u8 hdr) { + if (hdr < 0x20) + return 1; + if (hdr < 0x80) + return (2 + ((hdr - 0x20) >> 4)); + if (hdr < 0xe0) + return (8 + ((hdr - 0x80) >> 3)); + return (20 + ((hdr - 0xe0) >> 2)); +} + +void idtp922x_clrInt(struct idtp9220_device_info *di, u8 *buf, u32 size) { + di->bus.write_buf(di, REG_SSINTCLR, buf, size); + di->bus.write(di, REG_SSCMND, CLRINT); +} + +void idtp922x_sendPkt(struct idtp9220_device_info *di, ProPkt_Type *pkt) { + u32 size = ExtractPacketSize(pkt->header)+1; + di->bus.write_buf(di, REG_PROPPKT, (u8 *)pkt, size); // write data into proprietary packet buffer + di->bus.write(di, REG_SSCMND, SENDPROPP); // send proprietary packet + + dev_info(di->dev, "pkt header: 0x%x and cmd: 0x%x\n", + pkt->header, pkt->cmd); + di->header = pkt->header; + di->cmd = pkt->cmd; +} + +void idtp922x_receivePkt(struct idtp9220_device_info *di, u8 *buf) { + u8 header; + int rc; + u32 size; + + di->bus.read(di, REG_BCHEADER, &header); + size = ExtractPacketSize(header)+1; + rc = di->bus.read_buf(di, REG_BCDATA, buf, size); + if (rc < 0) + dev_err(di->dev, "[idt] read Tx data error: %d\n", rc); +} + +void idtp922x_set_adap_vol(struct idtp9220_device_info *di, u16 mv) +{ + dev_info(di->dev, "set adapter vol to %d\n", mv); + di->bus.write(di, REG_FC_VOLTAGE_L, mv&0xff); + di->bus.write(di, REG_FC_VOLTAGE_H, (mv>>8)&0xff); + di->bus.write(di, REG_SSCMND, VSWITCH); +} + + +void idtp922x_set_pmi_icl(struct idtp9220_device_info *di, int mA) +{ + union power_supply_propval val = {0, }; + int rc; + + rc = idtp9220_get_property_names(di); + val.intval = mA; + power_supply_set_property(di->dc_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &val); +} + +/* Adapter Type */ +/* Adapter_list = {0x00:'ADAPTER_UNKNOWN', */ +/* 0x01:'SDP 500mA', */ +/* 0x02:'CDP 1.1A', */ +/* 0x03:'DCP 1.5A', */ +/* 0x05:'QC2.0', */ +/* 0x06:'QC3.0', */ +/* 0x07:'PD',} */ +void idtp922x_request_adapter(struct idtp9220_device_info *di) +{ + ProPkt_Type pkt; + pkt.header = PROPRIETARY18; + pkt.cmd = BC_ADAPTER_TYPE; + + idtp922x_sendPkt(di, &pkt); +} + +void idtp922x_request_uuid(struct idtp9220_device_info *di, int is_epp) +{ + ProPkt_Type pkt; + pkt.header = PROPRIETARY18; + if(is_epp) + pkt.cmd = BC_TX_HWID; + else + pkt.cmd = BC_TX_COMPATIBLE_HWID; + idtp922x_sendPkt(di, &pkt); +} + +void idtp922x_get_tx_vin(struct idtp9220_device_info *di) +{ + ProPkt_Type pkt; + pkt.header = PROPRIETARY18; + pkt.cmd = BC_READ_Vin; + + idtp922x_sendPkt(di, &pkt); +} + +void idtp922x_retry_cmd(struct idtp9220_device_info *di) +{ + ProPkt_Type pkt; + pkt.header = di->header; + pkt.cmd = di->cmd; + + idtp922x_sendPkt(di, &pkt); +} + +static void idtp9220_int_enable(struct idtp9220_device_info *di) +{ + u8 int_val; + di->bus.read(di, REG_INTR_EN_L, &int_val); + di->bus.write(di, REG_INTR_EN_L, (int_val | OVER_EVENT_OCCUR)); + dev_info(di->dev, "[idtp9220]: int enabled status 0x%x\n", (int_val | OVER_EVENT_OCCUR)); +} + + +static int idtp9220_get_vout_regulator(struct idtp9220_device_info *di) +{ + u8 vout_l, vout_h; + u16 vout; + + if(!di) + return 0; + + di->bus.read(di, REG_REGULATOR_L, &vout_l); + di->bus.read(di, REG_REGULATOR_H, &vout_h); + vout = vout_l | ((vout_h & 0xff)<< 8); + dev_info(di->dev, "vout regulator get vol: %d\n", vout); + + return vout; +} + +void idtp9220_set_toggle_mode(struct idtp9220_device_info *di) +{ + ProPkt_Type pkt; + pkt.header = PROPRIETARY18; + pkt.cmd = BC_TX_TOGGLE; + idtp922x_sendPkt(di, &pkt); +} + +void idtp9220_retry_id_auth(struct idtp9220_device_info *di) +{ + ProPkt_Type pkt; + pkt.header = PROPRIETARY38; + pkt.cmd = BC_RX_ID_AUTH; + + pkt.data[0] = 0x02; + pkt.data[1] = 0xbb; + + idtp922x_sendPkt(di, &pkt); +} + +static int idtp9220_set_vout_regulator(struct idtp9220_device_info *di, int mv) +{ + u8 vout_l, vout_h; + u16 vout; + + if(!di) + return 0; + vout_l = mv & 0xff; + vout_h = mv >> 8; + + dev_info(di->dev, "vout regulator vout_l: 0x%x and vout_h: 0x%x\n", vout_l, vout_h); + di->bus.write(di, REG_REGULATOR_L, vout_l); + di->bus.write(di, REG_REGULATOR_H, vout_h); + + vout = vout_l | ((vout_h & 0xff) << 8); + dev_info(di->dev, "vout regulator set vol: %d\n", vout); + + return vout; +} + +static int idtp9220_get_vbuck(struct idtp9220_device_info *di) +{ + u8 vbuck_l, vbuck_h; + u16 vbuck_ret; + + if(!di) + return 0; + + di->bus.read(di, 0x08, &vbuck_l); + di->bus.read(di, 0x09, &vbuck_h); + vbuck_ret = vbuck_l | (vbuck_h << 8); + + return vbuck_ret; +} + + +static int idtp9220_get_vout(struct idtp9220_device_info *di) +{ + u8 vout_l, vout_h; + + if(!di) + return 0; + + di->bus.read(di, REG_ADC_VOUT_L, &vout_l); + di->bus.read(di, REG_ADC_VOUT_H, &vout_h); + di->vout = vout_l | ((vout_h & 0xf)<< 8); + di->vout = di->vout * 10 * 21 * 1000 / 40950 + ADJUST_METE_MV; //vout = val/4095*10*2.1 + + return di->vout; +} + +static void idtp9220_set_vout(struct idtp9220_device_info *di, int mv) +{ + u8 val; + if(!di) + return; + val = (mv -3500)/100; + di->bus.write(di, REG_VOUT_SET, val); + dev_info(di->dev, "[idtp9220]: set vout voltage is 0x%x\n", val); +} + +static void idtp9220_set_reset(struct idtp9220_device_info *di) +{ + if(!di) + return; + di->bus.write(di, REG_RX_RESET, 0x01); + dev_info(di->dev, "[idtp9220]: set RX reset\n"); +} +extern char *saved_command_line; + +static int get_cmdline(struct idtp9220_device_info *di) +{ + if (strnstr(saved_command_line, "androidboot.mode=", + strlen(saved_command_line))) { + + di->power_off_mode = 1; + dev_info(di->dev, "[idtp9220]: enter power off charging app\n"); + } else { + di->power_off_mode = 0; + dev_info(di->dev, "[idtp9220]: enter normal boot mode\n"); + } + return 1; +} + +static int idtp9220_get_iout(struct idtp9220_device_info *di) +{ + u8 cout_l, cout_h; + + if(!di) + return 0; + + di->bus.read(di, REG_RX_LOUT_L, &cout_l); + di->bus.read(di, REG_RX_LOUT_H, &cout_h); + di->iout = cout_l | (cout_h << 8); + + return di->iout; +} + +static int idtp9220_get_power_profile(struct idtp9220_device_info *di) +{ + u8 mode; + int ret; + + di->bus.read(di, REG_WPC_MODE, &mode); + ret = mode & BIT(3); + dev_info(di->dev, "tx is epp ? ret is 0x%x\n", mode); + + return ret; +} + + +static int idtp9220_get_freq(struct idtp9220_device_info *di) +{ + u8 data_list[2]; + + di->bus.read_buf(di, REG_FREQ_ADDR, data_list, 2); + di->f = 64*HSCLK/(data_list[0] | (data_list[1] << 8))/10; + + return di->f; +} + +static int idtp9220_get_vrect(struct idtp9220_device_info *di) +{ + u8 data_list[2]; + + di->bus.read_buf(di, REG_ADC_VRECT, data_list, 2); + di->vrect = data_list[0] | ((data_list[1] & 0xf)<< 8); + di->vrect = di->vrect * 10 * 21 * 1000 / 40950; //vrect = val/4095*10*2.1 + + return di->vrect; +} + +static int idtp9220_get_power_max(struct idtp9220_device_info *di) +{ + int power_max; + u8 val; + + di->bus.read(di, REG_POWER_MAX, &val); + power_max = (val/2)*1000; + dev_info(di->dev, "rx power max is %dmW\n", power_max); + + return power_max; +} + +static void idtp9220_send_device_auth(struct idtp9220_device_info *di) +{ + di->bus.write(di, REG_SSCMND, SEND_DEVICE_AUTH); +} + + +static ssize_t chip_version_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + u8 chip_id_l, chip_id_h, chip_rev, cust_id, status, vset; + u8 fw_otp_ver[4], fw_app_ver[4]; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + di->bus.read(di, REG_STATUS_L, &status); + di->bus.read(di, REG_VOUT_SET, &vset); + + di->bus.read(di, REG_CHIP_ID_L, &chip_id_l); + di->bus.read(di, REG_CHIP_ID_H, &chip_id_h); + di->bus.read(di, REG_CHIP_REV, &chip_rev); + chip_rev = chip_rev >> 4; + di->bus.read(di, REG_CTM_ID, &cust_id); + di->bus.read_buf(di, REG_OTPFWVER_ADDR, fw_otp_ver, 4); + di->bus.read_buf(di, REG_EPRFWVER_ADDR, fw_app_ver, 4); + + return sprintf(buf, "chip_id_l:%02x\nchip_id_h:%02x\nchip_rev:%02x\ncust_id:%02x status:%02x vset:%02x\n otp_ver:%x.%x.%x.%x\n app_ver:%x.%x.%x.%x\n", + chip_id_l, chip_id_h, chip_rev, cust_id, status, vset, + fw_otp_ver[0], fw_otp_ver[1], fw_otp_ver[2], fw_otp_ver[3], + fw_app_ver[0], fw_app_ver[1], fw_app_ver[2], fw_app_ver[3]); +} + +/* voltage limit attrs */ +static ssize_t chip_vout_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + int vout; + + vout = idtp9220_get_vout(di); + return sprintf(buf, "Vout ADC Value: %dMV\n", vout); + +} + +static ssize_t chip_vout_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int index; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + + index = (int)simple_strtoul(buf, NULL, 16); +/* + if ((index < VOUT_VAL_3500_MV) || (index > VOUT_VAL_5000_MV)) { + dev_err(di->dev, "Store Val %s is invalid!\n", buf); + return count; + } +*/ + + idtp9220_set_vout(di, index); + + return count; +} + +static ssize_t vout_regulator_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + int vout; + + vout = idtp9220_get_vout_regulator(di); + + return sprintf(buf, "Vout ADC Value: %dMV\n", vout); +} + +#define VOUT_MIN_4900_MV 4900 +#define VOUT_MAX_10000_MV 10000 +static ssize_t vout_regulator_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int vout; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + + vout = (int)simple_strtoul(buf, NULL, 10); + if ((vout <= VOUT_MIN_4900_MV) || (vout > VOUT_MAX_10000_MV)) { + dev_err(di->dev, "Store Val %s : %ld is invalid!\n", buf, vout ); + return count; + } + idtp9220_set_vout_regulator(di, vout); + + return count; +} + +/* current attrs */ +static ssize_t chip_iout_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + int cout; + + cout = idtp9220_get_iout(di); + + return sprintf(buf, "Output Current: %dMA\n", cout); +} + +static ssize_t chip_iout_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int index; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + + index = (int)simple_strtoul(buf, NULL, 10); + + if ((index < CURR_VAL_100_MA) || (index > CURR_VAL_1300_MA)) { + dev_err(di->dev, "Store Val %s is invalid", buf); + return count; + } + + di->bus.write(di, REG_ILIM_SET, index); + + return count; +} + +static ssize_t chip_freq_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + int f; + + f = idtp9220_get_freq(di); + + return sprintf(buf, "Output Current: %dkHz\n", f); +} + +static void idtp9220_charging_info(struct idtp9220_device_info *di) +{ + int vbuck_ret = 0; + if(!di) + return; + + idtp9220_get_vout(di); + idtp9220_get_iout(di); + idtp9220_get_freq(di); + idtp9220_get_vrect(di); + vbuck_ret = idtp9220_get_vbuck(di); + + dev_info(di->dev, "%s:Vout:%dmV,Iout:%dmA,Freq:%dKHz,Vrect:%dmV,SS:%d, Vbuck:%d\n", __func__, + di->vout, di->iout, di->f, di->vrect, di->ss, vbuck_ret); +} + +/* chip enable attrs */ +static ssize_t chip_enable_show(struct device *dev, + struct device_attribute *attr, + char *buf) +{ + int ret; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + + if (gpio_is_valid(di->dt_props.enable_gpio)) + ret = gpio_get_value(di->dt_props.enable_gpio); + else { + dev_err(di->dev, "%s: sleep gpio not provided\n", __func__); + ret = -1; + } + + dev_info(di->dev, "chip enable gpio: %d\n", ret); + + return sprintf(buf, "Chip enable: %d\n", !ret); +} + +static int idtp9220_set_present(struct idtp9220_device_info *di, int enable) +{ + int ret = 0; + + dev_info(di->dev, "[idtp] dc plug %s\n", enable ? "in" : "out"); + if(enable) + { + di->dcin_present = true; + di->ss = 1; + } else { + schedule_delayed_work(&di->fast_operate_work, msecs_to_jiffies(200)); + di->status = NORMAL_MODE; + di->count_9v = 0; + di->count_5v = 0; + di->count_12v = 0; + di->count_15v = 0; + di->exchange = 0; + di->epp_exchange = 0; + di->dcin_present = false; + idt_signal_range = 2; + di->ss = 2; + di->vbuck = 0; + di->epp = 0; + di->last_vin = 0; + di->last_icl = 0; + di->last_vbuck = 0; + di->is_car_tx = 0; + di->power_off_mode = 0; + di->is_epp_qc3 = 0; + di->is_vin_limit = 0; + di->bpp_vout_rise = 0; + di->is_f1_tx = 0; + di->last_bpp_vout = 0; + di->last_bpp_icl = 0; + di->last_qc2_vout = 0; + di->last_qc2_icl = 0; + di->last_qc3_vout = 0; + di->last_qc3_icl = 0; + di->tx_charger_type = ADAPTER_NONE; + cancel_delayed_work(&di->chg_monitor_work); + cancel_delayed_work(&di->cmd_check_work); + } + + return ret; +} + + +static int idtp9220_set_enable_mode(struct idtp9220_device_info *di, int enable) +{ + int ret = 0; + + if (gpio_is_valid(di->dt_props.enable_gpio)) { + ret = gpio_request(di->dt_props.enable_gpio, + "idt-enable-gpio"); + if (ret) { + dev_err(di->dev, + "%s: unable to request idt enable gpio [%d]\n", + __func__, di->dt_props.enable_gpio); + } + + ret = gpio_direction_output(di->dt_props.enable_gpio, !enable); + if (ret) { + dev_err(di->dev, + "%s: cannot set direction for idt enable gpio [%d]\n", + __func__, di->dt_props.enable_gpio); + } + gpio_free(di->dt_props.enable_gpio); + } + + return ret; +} + +static ssize_t chip_enable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, + size_t count) +{ + int ret, enable; + struct i2c_client *client = container_of(dev, struct i2c_client, dev); + struct idtp9220_device_info *di = i2c_get_clientdata(client); + + ret = (int)simple_strtoul(buf, NULL, 10); + enable = !!ret; + + idtp9220_set_enable_mode(di, enable); + + return count; +} + +static DEVICE_ATTR(chip_enable, S_IWUSR | S_IRUGO, chip_enable_show, chip_enable_store); +static DEVICE_ATTR(chip_version, S_IRUGO, chip_version_show, NULL); +static DEVICE_ATTR(chip_vout, S_IWUSR | S_IRUGO, chip_vout_show, chip_vout_store); +static DEVICE_ATTR(chip_iout, S_IWUSR | S_IRUGO, chip_iout_show, chip_iout_store); +static DEVICE_ATTR(chip_freq, S_IRUGO, chip_freq_show, NULL); +static DEVICE_ATTR(vout_regulator, S_IWUSR | S_IRUGO, vout_regulator_show, vout_regulator_store); + +static struct attribute *sysfs_attrs[] = { + &dev_attr_chip_version.attr, + &dev_attr_chip_vout.attr, + &dev_attr_chip_iout.attr, + &dev_attr_chip_freq.attr, + &dev_attr_chip_enable.attr, + &dev_attr_vout_regulator.attr, + NULL, +}; + +static const struct attribute_group sysfs_group_attrs = { + .attrs = sysfs_attrs, +}; + +static int idtp9220_parse_dt(struct idtp9220_device_info *di) +{ + struct device_node *node = di->dev->of_node; + + if (!node) { + dev_err(di->dev, "device tree node missing\n"); + return -EINVAL; + } + + di->dt_props.irq_gpio = of_get_named_gpio(node, "idt,irq", 0); + if ((!gpio_is_valid(di->dt_props.irq_gpio))) + return -EINVAL; + + di->dt_props.enable_gpio = of_get_named_gpio(node, "idt,enable", 0); + if ((!gpio_is_valid(di->dt_props.enable_gpio))) + return -EINVAL; + + di->dt_props.wpc_det_gpio = of_get_named_gpio(node, "idt,wpc-det", 0); + if ((!gpio_is_valid(di->dt_props.irq_gpio))) + return -EINVAL; + + return 0; +} + +static int idtp9220_gpio_init(struct idtp9220_device_info *di) +{ + int ret = 0; + int irqn = 0; + int wpc_irq = 0; + + di->idt_pinctrl = devm_pinctrl_get(di->dev); + if (IS_ERR_OR_NULL(di->idt_pinctrl)) { + dev_err(di->dev, "No pinctrl config specified\n"); + ret = PTR_ERR(di->dev); + return ret; + } + di->idt_gpio_active = + pinctrl_lookup_state(di->idt_pinctrl, "idt_active"); + if (IS_ERR_OR_NULL(di->idt_gpio_active)) { + dev_err(di->dev, "No active config specified\n"); + ret = PTR_ERR(di->idt_gpio_active); + return ret; + } + di->idt_gpio_suspend = + pinctrl_lookup_state(di->idt_pinctrl, "idt_suspend"); + if (IS_ERR_OR_NULL(di->idt_gpio_suspend)) { + dev_err(di->dev, "No suspend config specified\n"); + ret = PTR_ERR(di->idt_gpio_suspend); + return ret; + } + + ret = pinctrl_select_state(di->idt_pinctrl, + di->idt_gpio_active); + if (ret < 0) { + dev_err(di->dev, "fail to select pinctrl active rc=%d\n", + ret); + return ret; + } + + if (gpio_is_valid(di->dt_props.irq_gpio)) { + irqn = gpio_to_irq(di->dt_props.irq_gpio); + if (irqn < 0) { + ret = irqn; + goto err_irq_gpio; + } + di->irq = irqn; + } else { + dev_err(di->dev, "%s: irq gpio not provided\n", __func__); + goto err_irq_gpio; + } + + if (gpio_is_valid(di->dt_props.wpc_det_gpio)) { + wpc_irq = gpio_to_irq(di->dt_props.wpc_det_gpio); + if (wpc_irq < 0) { + ret = wpc_irq; + goto err_wpc_irq; + } + di->wpc_irq = wpc_irq; + } else { + dev_err(di->dev, "%s: wpc irq gpio not provided\n", __func__); + goto err_wpc_irq; + } + +err_wpc_irq: + gpio_free(di->dt_props.wpc_det_gpio); +err_irq_gpio: + gpio_free(di->dt_props.irq_gpio); + return ret; +} + +static bool need_irq_cleared(struct idtp9220_device_info *di) +{ + u8 int_buf[2]; + u16 int_val; + int rc = -1; + + rc = di->bus.read_buf(di, REG_INTR_L, int_buf, 2); + if (rc < 0) { + dev_err(di->dev, "%s: read int state error\n", __func__); + return true; + } + int_val = int_buf[0] | (int_buf[1] << 8); + if (int_val != 0) { + dev_info(di->dev, "irq not clear right: 0x%04x\n", int_val); + return true; + } + + if (gpio_is_valid(di->dt_props.irq_gpio)) + rc = gpio_get_value(di->dt_props.irq_gpio); + else { + dev_err(di->dev, "%s: irq gpio not provided\n", __func__); + rc = -1; + } + if (!rc) { + dev_info(di->dev, "irq low, need clear int: %d\n", rc); + return true; + } + return false; +} + +#define VBUCK_QC_VOL 7000 +#define VBUCK_FULL_VOL 7000 +#define VBUCK_DEFAULT_VOL 5500 +#define ADAPTER_BPP_QC_VOL 9000 +#define ADAPTER_BPP_LIMIT_VOL 6500 +#define BPP_VOL_THRESHOLD 8000 +#define ADAPTER_BPP_VOL 5000 +#define ADAPTER_EPP_MI_VOL 15000 +#define EPP_VOL_THRESHOLD 12000 +#define EPP_VOL_LIM_THRESHOLD 13000 +#define BPP_VOL_LIM_THRESHOLD 10000 +#define CHARGING_PERIOD_S 10 +#define TAPER_CURR_Limit 950000 + +static void idtp9220_monitor_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + chg_monitor_work.work); + + idtp9220_charging_info(di); + + idtp9220_set_charging_param(di); + + schedule_delayed_work(&di->chg_monitor_work, + CHARGING_PERIOD_S * HZ); +} + +static void idtp9220_rx_vout_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + rx_vout_work.work); + + idtp9220_set_charging_param(di); + +} + +static void idtp9220_dc_check_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + dc_check_work.work); + + dev_info(di->dev, "[idt] dc present: %d\n", di->dcin_present); + if (di->dcin_present) { + di->ss = 1; + dev_info(di->dev, "dcin present, quit dc check work\n"); + return; + } else { + di->ss = 0; + dev_info(di->dev, "dcin no present, continue dc check work\n"); + schedule_delayed_work(&di->dc_check_work, msecs_to_jiffies(2500)); + } + power_supply_changed(di->idtp_psy); +} + +static void idtp9220_fast_operate_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + fast_operate_work.work); + int ret = -1; + int usb_present, typec_mode; + union power_supply_propval val = {0, }; + + ret = idtp9220_get_property_names(di); + if(ret < 0) + return; + + power_supply_get_property(di->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &val); + usb_present = val.intval; + + power_supply_get_property(di->usb_psy, + POWER_SUPPLY_PROP_TYPEC_MODE, &val); + typec_mode = val.intval; + + dev_info(di->dev, "usb present:%d typec mode:%d\n", + usb_present, typec_mode); + + if (gpio_is_valid(di->dt_props.wpc_det_gpio)) { + ret = gpio_get_value(di->dt_props.wpc_det_gpio); + /* power good irq will not trigger after insert typec audio/charger + * connector while wireless charging. WR for this situation. + */ + if ((!usb_present && ret) || (usb_present && ret + && (typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER + || typec_mode == POWER_SUPPLY_TYPEC_NONE))){ + dev_info(di->dev, "dc out but power_good high, reset by sleep\n"); + idtp9220_set_enable_mode(di, false); + msleep(10); + idtp9220_set_enable_mode(di, true); + } + } +} + +static void idtp9220_chg_detect_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + chg_detect_work.work); + + union power_supply_propval val = {0, }; + union power_supply_propval wk_val = {0, }; + int rc; + + dev_info(di->dev, "[idt] enter %s\n", __func__); + + rc = idtp9220_get_property_names(di); + if(rc < 0) + return; + + /*set idtp9220 into sleep mode when usbin*/ + + power_supply_get_property(di->usb_psy, + POWER_SUPPLY_PROP_ONLINE, &val); + if(val.intval) { + dev_info(di->dev, "[idt] usb_online:%d set chip disable\n", val.intval); + idtp9220_set_enable_mode(di, false); + return; + } + + if(di->dc_psy) { + power_supply_get_property(di->dc_psy, + POWER_SUPPLY_PROP_ONLINE, &val); + dev_info(di->dev, "[idt] dc_online %d\n", val.intval); + if(val.intval && di->wireless_psy) { + idtp9220_int_enable(di); + wk_val.intval = 1; + power_supply_set_property(di->wireless_psy, + POWER_SUPPLY_PROP_WIRELESS_WAKELOCK, &wk_val); + di->epp = idtp9220_get_power_profile(di); + + get_cmdline(di); + if (!di->power_off_mode) + idtp9220_set_reset(di); + else + schedule_delayed_work(&di->irq_work, + msecs_to_jiffies(30)); + } + } +} + +#define DC_LOAD_CURRENT 2000000 +#define DC_FUL_CURRENT 50000 +#define SCREEN_OFF_FUL_CURRENT 220000 +#define DC_LOW_CURRENT 350000 +#define DC_SDP_CURRENT 500000 +#define DC_DCP_CURRENT 500000 +#define DC_PD_CURRENT 800000 +#define DC_MI_CURRENT 2100000 +#define DC_MI_STEP1_CURRENT 1200000 +#define DC_QC3_CURRENT 1400000 +#define DC_QC2_CURRENT 1100000 +#define DC_BPP_CURRENT 850000 +#define DC_BPP_AUTH_FAIL_CURRENT 800000 +#define ICL_EXCHANGE_CURRENT 600000 +#define ICL_EXCHANGE_COUNT 5 /*5 = 1min*/ +#define EXCHANGE_9V 0x0 +#define EXCHANGE_5V 0x1 +#define EXCHANGE_15V 0x0 +#define EXCHANGE_12V 0x1 +#define LIMIT_EPP_IOUT 500 +#define LIMIT_BPP_IOUT 400 +#define LIMIT_SOC 80 +#define TAPER_SOC 95 +#define FULL_SOC 100 +#define TAPER_VOL 4350000 +#define TAPER_CUR -500000 + +static void idtp9220_bpp_connect_load_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + bpp_connect_load_work.work); + + idtp922x_set_pmi_icl(di, DC_DCP_CURRENT); + +} + +static void idtp9220_epp_connect_load_work(struct work_struct *work) +{ + + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + epp_connect_load_work.work); + int dc_load_curr = 0; + + if (di->power_max <= 10000) + dc_load_curr = (di->power_max - 1000)/5 * 1000; + else + dc_load_curr = DC_LOAD_CURRENT; + + idtp922x_set_pmi_icl(di, dc_load_curr); + +} + +static void idtp9220_cmd_check_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + cmd_check_work.work); + + dev_info(di->dev, "[idt] %s: \n", __func__); + idtp922x_get_tx_vin(di); + if (di->power_off_mode) { + schedule_delayed_work(&di->vout_regulator_work, + msecs_to_jiffies(10)); + } + +} + +static void idtp9220_mophie_tx_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + mophie_tx_work.work); + int ret = 0; + u8 buf[2] = {0}; + u16 int_val = 0; + + ret = idtp9220_get_power_profile(di); + if (ret) { + ret = di->bus.read_buf(di, REG_TX_TYPE, buf, 2); + if (ret < 0) + dev_err(di->dev, "read tx type error: %d\n", ret); + else { + int_val = buf[0] | (buf[1] << 8); + dev_info(di->dev, "tx type: 0x%04x\n", int_val); + if (int_val == 0x0059) { + dev_info(di->dev, "write vrect target\n"); + di->bus.write(di, 0x0090, 0x0); + di->bus.write(di, 0x0091, 0x8); + di->bus.write(di, 0x003E, 0x41); + } + } + } + +} + +static void idtp9220_bpp_e5_tx_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + bpp_e5_tx_work.work); + int icl_curr = 0, vbuck = 0, adapter_vol = 0; + int soc = 0, batt_sts = 0, health = 0; + int icl_setted = 0; + union power_supply_propval val = {0, }; + union power_supply_propval wk_val = {0, }; + + if (di->batt_psy) { + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_STATUS, &val); + batt_sts = val.intval; + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &val); + soc = val.intval; + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_HEALTH, &val); + health = val.intval; + } + + if (di->tx_charger_type == ADAPTER_QC3) { + adapter_vol = ADAPTER_BPP_QC_VOL; + vbuck = VBUCK_QC_VOL; + icl_curr = DC_QC3_CURRENT; + } else if (di->tx_charger_type == ADAPTER_QC2) { + adapter_vol = ADAPTER_BPP_QC_VOL; + vbuck = VBUCK_QC_VOL; + icl_curr = DC_QC2_CURRENT; + } + + if (di->iout < LIMIT_BPP_IOUT && di->exchange == EXCHANGE_9V) { + di->count_5v++; + di->count_9v = 0; + } else if (di->iout > LIMIT_BPP_IOUT && di->exchange == EXCHANGE_5V) { + di->count_9v++; + di->count_5v = 0; + } else { + di->count_5v = 0; + di->count_9v = 0; + } + /* + * 9V-->5V check 6 times + * 5V-->9v check 3 times + */ + if(di->count_5v > ICL_EXCHANGE_COUNT || + (di->exchange == EXCHANGE_5V && di->count_9v <= ICL_EXCHANGE_COUNT - 3)) + { + dev_info(di->dev, "iout less than 500mA ,set vout to 6.5v\n"); + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = DC_BPP_CURRENT; + di->exchange = EXCHANGE_5V; + } else if (di->count_9v > (ICL_EXCHANGE_COUNT - 3)) + di->exchange = EXCHANGE_9V; + + if (soc > 90) + icl_curr = DC_BPP_CURRENT; + + switch (di->status) { + case NORMAL_MODE: + if (soc >= TAPER_SOC) { + di->status = TAPER_MODE; + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = min(DC_SDP_CURRENT, icl_curr); + } + break; + case TAPER_MODE: + dev_info (di->dev, "[bpp] taper mode set vout to 6.5v\n"); + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = min(DC_SDP_CURRENT, icl_curr); + + if (soc == FULL_SOC && batt_sts == POWER_SUPPLY_STATUS_FULL) + di->status = FULL_MODE; + else if (soc < TAPER_SOC - 1) + di->status = NORMAL_MODE; + break; + case FULL_MODE: + dev_info (di->dev, "[bpp] charge full set vout to 6.5v\n"); + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = SCREEN_OFF_FUL_CURRENT; + + if (batt_sts == POWER_SUPPLY_STATUS_CHARGING) { + di->status = RECHG_MODE; + icl_curr = DC_LOW_CURRENT; + } + break; + case RECHG_MODE: + dev_info (di->dev, "[bpp] recharge mode set icl to 300mA\n"); + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = DC_LOW_CURRENT; + + if (soc < TAPER_SOC - 1) + di->status = NORMAL_MODE; + else if (batt_sts == POWER_SUPPLY_STATUS_FULL) + di->status = FULL_MODE; + + if (di->wireless_psy) { + wk_val.intval = 1; + power_supply_set_property(di->wireless_psy, + POWER_SUPPLY_PROP_WIRELESS_WAKELOCK, &wk_val); + } + break; + default: + break; + } + + switch(health) { + case POWER_SUPPLY_HEALTH_GOOD: + break; + case POWER_SUPPLY_HEALTH_COOL: + break; + case POWER_SUPPLY_HEALTH_WARM: + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = min(DC_SDP_CURRENT, icl_curr); + break; + case POWER_SUPPLY_HEALTH_OVERVOLTAGE: + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = min(SCREEN_OFF_FUL_CURRENT, icl_curr); + break; + case POWER_SUPPLY_HEALTH_COLD: + case POWER_SUPPLY_HEALTH_HOT: + adapter_vol = ADAPTER_BPP_LIMIT_VOL; + vbuck = VBUCK_DEFAULT_VOL; + icl_curr = SCREEN_OFF_FUL_CURRENT; + break; + default: + break; + } + + if (adapter_vol != di->last_bpp_vout) { + dev_info(di->dev, "bpp_10w, set new vout: %d, last_vout: %d\n", + adapter_vol, di->last_bpp_vout); + if (adapter_vol > BPP_VOL_THRESHOLD) { + idtp922x_set_adap_vol(di, adapter_vol); + msleep(200); + idtp9220_set_vout_regulator(di, vbuck); + msleep(200); + } else { + idtp9220_set_vout_regulator(di, 5800); + msleep(100); + idtp922x_set_pmi_icl(di, 100000); + msleep(100); + idtp922x_set_adap_vol(di, adapter_vol); + msleep(2000); + idtp922x_set_pmi_icl(di, DC_SDP_CURRENT); + msleep(100); + icl_setted = 1; + } + di->last_bpp_vout = adapter_vol; + } + + if ((icl_curr != di->last_bpp_icl) || (icl_setted)) { + dev_info(di->dev, "bpp_10w, set new icl: %d, last_icl: %d\n", + icl_curr, di->last_bpp_icl); + di->last_bpp_icl = icl_curr; + if ((adapter_vol == ADAPTER_BPP_QC_VOL) && (!di->bpp_vout_rise)) { + dev_info(di->dev, "bpp_10w, vout lower than 8v, set 500mA\n"); + icl_curr = min(DC_SDP_CURRENT, icl_curr); + } + idtp922x_set_pmi_icl(di, icl_curr); + } +} + +static void idtp9220_qc2_f1_tx_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + qc2_f1_tx_work.work); + int soc = 0, batt_sts = 0; + int vout = VOUT_VAL_6500_MV; + int dc_icl = DC_QC2_CURRENT; + union power_supply_propval val = {0, }; + + if (di->batt_psy) { + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_STATUS, &val); + batt_sts = val.intval; + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &val); + soc = val.intval; + } + + if (vout != di->last_qc2_vout) { + dev_info(di->dev, "qc2+f1_tx, set new vout: %d, last_vout: %d\n", + vout, di->last_qc2_vout); + di->last_qc2_vout = vout; + di->bus.write(di, 0x003E, vout); + msleep(100); + idtp9220_set_vout_regulator(di, VBUCK_DEFAULT_VOL); + msleep(100); + } + + if (dc_icl != di->last_qc2_icl) { + dev_info(di->dev, "qc2+f1_tx, set new icl: %d, last_icl: %d\n", + dc_icl, di->last_qc2_icl); + di->last_qc2_icl = dc_icl; + idtp922x_set_pmi_icl(di, dc_icl); + } +} + +static void idtp9220_qc3_epp_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + qc3_epp_work.work); + int adapter_vol = 0; + int dc_icl = DC_MI_STEP1_CURRENT; + + if (adapter_vol != di->last_qc3_vout) { + dev_info(di->dev, "qc3 epp, set new vout: %d, last_vout: %d\n", + adapter_vol, di->last_qc3_vout); + di->last_qc3_vout = adapter_vol; + idtp922x_set_adap_vol(di, adapter_vol); + msleep(200); + } + + if (dc_icl != di->last_qc3_icl) { + dev_info(di->dev, "qc3_epp, set new icl: %d, last_icl: %d\n", + dc_icl, di->last_qc3_icl); + di->last_qc3_icl = dc_icl; + if (dc_icl == DC_MI_STEP1_CURRENT) { + schedule_delayed_work(&di->vout_regulator_work, + msecs_to_jiffies(0)); + } + idtp922x_set_pmi_icl(di, dc_icl); + } +} + +static void idtp9220_vout_regulator_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + vout_regulator_work.work); + + union power_supply_propval val = {0, }; + int ret; + int vinc = 0; + int soc = 0; + + if (di->batt_psy) { + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &val); + soc = val.intval; + } + + if(di) + idtp9220_get_vout(di); + else + return; + + if(di->epp) + vinc = (di->vout > EPP_VOL_THRESHOLD) ? 1 : 0; + else + vinc = (di->vout > BPP_VOL_THRESHOLD) ? 1 : 0; + + if (vinc && !di->epp) { + di->bpp_vout_rise = 1; + goto out; + } else if (!vinc && !di->epp) { + di->bpp_vout_rise = 0; + goto out; + } + + if(di->epp && (vinc || di->is_epp_qc3 || di->is_vin_limit) && soc < 95) { + ret = idtp9220_get_property_names(di); + if (di->wireless_psy) { + val.intval = 1; + power_supply_set_property(di->wireless_psy, POWER_SUPPLY_PROP_WIRELESS_CP_EN, &val); + msleep(200); + if(!di->is_epp_qc3 && !di->is_vin_limit) + idtp922x_set_pmi_icl(di, DC_MI_CURRENT); + } else + dev_err(di->dev, "[idt] no wireless psy\n"); + } +out: + dev_info(di->dev, "[idt] %s: epp=%d vbuck=%d vout= %d\n", __func__, di->epp, di->vbuck, di->vout); + return; +} + +static void idtp9220_set_charging_param(struct idtp9220_device_info *di) +{ + int soc = 0, health = 0, batt_sts = 0; + int adapter_vol = 0, icl_curr = 0; + int cur_now = 0, vol_now = 0, vin_inc = 0; + union power_supply_propval val = {0, }; + + switch (di->tx_charger_type) { + case ADAPTER_QC2: + adapter_vol = ADAPTER_BPP_QC_VOL; + di->vbuck = VBUCK_QC_VOL; + icl_curr = DC_QC2_CURRENT; + break; + case ADAPTER_QC3: + if(!di->epp) { + adapter_vol = ADAPTER_BPP_QC_VOL; + di->vbuck = VBUCK_QC_VOL; + icl_curr = DC_QC3_CURRENT; + } else { + di->is_epp_qc3 = 1; + icl_curr = DC_MI_STEP1_CURRENT; + } + break; + case ADAPTER_XIAOMI_PD: + case ADAPTER_PD: + if(di->epp) { + di->vbuck = VBUCK_QC_VOL; + icl_curr = DC_QC3_CURRENT; + } else { + di->vbuck = VBUCK_DEFAULT_VOL; + icl_curr = DC_PD_CURRENT; + } + break; + case ADAPTER_AUTH_FAILED: + if(di->epp) { + di->vbuck = VBUCK_QC_VOL; + if (di->power_max <= 10000) + icl_curr = ((di->power_max - 1000) / (VBUCK_QC_VOL/1000)) * 1000; + else + icl_curr = DC_QC3_CURRENT; + } else { + di->vbuck = VBUCK_DEFAULT_VOL; + icl_curr = DC_BPP_AUTH_FAIL_CURRENT; + } + break; + case ADAPTER_DCP: + case ADAPTER_CDP: + di->vbuck = VBUCK_DEFAULT_VOL; + if (di->is_compatible_hwid) + icl_curr = DC_BPP_AUTH_FAIL_CURRENT; + else + icl_curr = DC_DCP_CURRENT; + break; + case ADAPTER_SDP: + di->vbuck = VBUCK_DEFAULT_VOL; + icl_curr = DC_SDP_CURRENT; + break; + case ADAPTER_XIAOMI_QC3: + case ADAPTER_ZIMI_CAR_POWER: + case ADAPTER_XIAOMI_PD_40W: + if(di->epp) { + adapter_vol = ADAPTER_EPP_MI_VOL; + icl_curr = DC_MI_STEP1_CURRENT; + } else { + di->vbuck = VBUCK_QC_VOL; + icl_curr = DC_QC3_CURRENT; + } + break; + default: + icl_curr = 0; + break; + } + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_STATUS, &val); + batt_sts = val.intval; + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &val); + soc = val.intval; + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); + vol_now = val.intval; + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_CURRENT_NOW, &val); + cur_now = val.intval; + + power_supply_get_property(di->batt_psy, + POWER_SUPPLY_PROP_HEALTH, &val); + health = val.intval; + + idtp9220_get_iout(di); + + if((batt_sts == POWER_SUPPLY_STATUS_DISCHARGING) + && di->dcin_present + && di->power_good_flag) { + dev_info(di->dev, "discharge when dc and pwr present, reset chip\n"); + schedule_delayed_work(&di->fast_operate_work, msecs_to_jiffies(0)); + return; + } + dev_info(di->dev, "[idtp] soc:%d,vol_now:%d,cur_now:%d,health:%d, bat_status:%d\n", + soc, vol_now, cur_now, health, batt_sts); + + /* adapter:qc2/qc3; tx:e5/d5x_10W; + * vout/vbuck/psns is setted in delayed work + */ + if(adapter_vol == ADAPTER_BPP_QC_VOL && di->is_compatible_hwid) { + schedule_delayed_work(&di->bpp_e5_tx_work, msecs_to_jiffies(0)); + goto out; + } + + /* adapter:qc2; tx:F1_27W; + * vout/vbuck/psns is setted in delayed work + */ + if (di->tx_charger_type == ADAPTER_QC2 && di->is_f1_tx) { + schedule_delayed_work(&di->qc2_f1_tx_work, msecs_to_jiffies(0)); + goto out; + } + + /* adapter:qc3_epp; tx:F1_27W; + * vout/vbuck/psns is setted in delayed work + */ + if (di->is_epp_qc3) { + schedule_delayed_work(&di->qc3_epp_work, msecs_to_jiffies(0)); + goto out; + } + + if (adapter_vol > 0 && adapter_vol != di->last_vin) { + idtp922x_set_adap_vol(di, adapter_vol); + vin_inc = 1; + di->last_vin = adapter_vol; + if (adapter_vol == ADAPTER_EPP_MI_VOL || adapter_vol == EPP_VOL_THRESHOLD) { + msleep(100); + idtp922x_set_pmi_icl(di, icl_curr); + di->last_icl = icl_curr; + if (di->is_vin_limit) + schedule_delayed_work(&di->vout_regulator_work, + msecs_to_jiffies(0)); + } + } else { + if (((di->tx_charger_type == ADAPTER_QC2) || (di->tx_charger_type == ADAPTER_QC3)) + && !di->epp && !di->bpp_vout_rise && icl_curr > DC_DCP_CURRENT) + dev_info(di->dev, "don't set curr with qc2/qc3 of bpp when vout low\n"); + else { + if (icl_curr > 0 && icl_curr != di->last_icl) { + idtp922x_set_pmi_icl(di, icl_curr); + di->last_icl = icl_curr; + } + msleep(150); + if (di->vbuck > 0 && di->vbuck != di->last_vbuck) { + idtp9220_set_vout_regulator(di, di->vbuck); + di->last_vbuck = di->vbuck; + } + } + } + + printk("[idtp] di->status:0x%x,adapter_vol =%d,icl_curr=%d, vbuck=%d, last_vin=%d, last_icl=%d\n", + di->status, adapter_vol, icl_curr, di->vbuck, di->last_vin, di->last_icl); + + if (adapter_vol == ADAPTER_EPP_MI_VOL || + adapter_vol == ADAPTER_BPP_QC_VOL || + adapter_vol == VBUCK_FULL_VOL) { + if (vin_inc && (!di->is_vin_limit && !di->is_epp_qc3)) + schedule_delayed_work(&di->cmd_check_work, + msecs_to_jiffies(8000)); + } + +out: + return; +} + +static void idtp9220_wpc_det_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + wpc_det_work.work); + union power_supply_propval val = {0, }; + int ret = 0; + + ret = idtp9220_get_property_names(di); + if (ret < 0) { + dev_err(di->dev, "get property error: %d\n", ret); + return; + } + + if (gpio_is_valid(di->dt_props.wpc_det_gpio)) { + ret = gpio_get_value(di->dt_props.wpc_det_gpio); + if (ret) { + /* check if mophie tx after 100ms */ + schedule_delayed_work(&di->mophie_tx_work, msecs_to_jiffies(100)); + /* check dc present to judge device skewing */ + schedule_delayed_work(&di->dc_check_work, msecs_to_jiffies(2500)); + di->power_good_flag = 1; + val.intval = 1; + idtp9220_int_enable(di); + } + else { + cancel_delayed_work(&di->dc_check_work); + di->power_good_flag = 0; + val.intval = 0; + di->ss = 2; + } + power_supply_set_property(di->wireless_psy, POWER_SUPPLY_PROP_WIRELESS_POWER_GOOD_EN, &val); + } + + return; +} + +static void idtp9220_irq_work(struct work_struct *work) +{ + struct idtp9220_device_info *di = + container_of(work, struct idtp9220_device_info, + irq_work.work); + u8 int_buf[2] = {0}; + u16 int_val = 0; + int rc = 0; + u8 recive_data[5] = {0}; + static int retry = 0; + static int retry_id = 0; + static int retry_count = 0; + int tx_vin = 0; + int irq_level; + + if (gpio_is_valid(di->dt_props.irq_gpio)) + irq_level = gpio_get_value(di->dt_props.irq_gpio); + else { + dev_err(di->dev, "%s: irq gpio not provided\n", __func__); + irq_level = -1; + return; + } + if(irq_level) { + return; + } + + rc = di->bus.read_buf(di, REG_INTR_L, int_buf, 2); + if (rc < 0) { + dev_err(di->dev, "[idt]read int state error: %d\n", rc); + goto out; + } + /* clear int and enable irq immediately when read int register*/ + idtp922x_clrInt(di, int_buf, 2); + + int_val = int_buf[0] | (int_buf[1] << 8); + dev_info(di->dev, "[idt] int: 0x%04x\n", int_val); + + msleep(5); + + if (need_irq_cleared(di)) + { + u8 clr_buf[2] = {0xFF, 0xFF}; + idtp922x_clrInt(di, clr_buf, 2); + msleep(5); + } + if ((int_val & INT_OV_CURR) || (int_val & INT_OV_TEMP)) { + dev_info(di->dev, "[idt] ocp or otp found \n"); + schedule_delayed_work(&di->chg_monitor_work, + msecs_to_jiffies(0)); + goto out; + } + + if(int_val & INT_VOUT_ON) { + di->epp = idtp9220_get_power_profile(di); + if(di->epp) { + di->power_max = idtp9220_get_power_max(di); + schedule_delayed_work(&di->epp_connect_load_work, + msecs_to_jiffies(0)); + } else + schedule_delayed_work(&di->bpp_connect_load_work, + msecs_to_jiffies(0)); + if (int_val & INT_IDAUTH_SUCESS) + idtp9220_send_device_auth(di); + goto out; + } + + if (int_val & INT_VSWITCH_SUCESS) { + schedule_delayed_work(&di->vout_regulator_work, + msecs_to_jiffies(50)); + cancel_delayed_work(&di->cmd_check_work); + goto out; + } + + if (int_val & INT_IDAUTH_SUCESS) { + idtp9220_send_device_auth(di); + //idtp922x_request_adapter(di); + goto out; + } + + + if(int_val & INT_AUTH_SUCESS) { + idtp922x_request_uuid(di, di->epp); + goto out; + } +/* + idtp9220_get_signal_strength(di); + di->tx_charger_type = ADAPTER_QC3; + schedule_delayed_work(&di->chg_monitor_work, + msecs_to_jiffies(0)); + goto out; +*/ + + if ((int_val & INT_IDAUTH_FAIL) || (int_val & INT_AUTH_FAIL) || int_val == 0) { + if(((int_val & INT_AUTH_FAIL) || (int_val == 0)) && (retry < 5)){ + idtp9220_send_device_auth(di); + retry++; + dev_info(di->dev, "[idtp] dev auth failed retry %d\n", retry); + goto out; + } else if ((int_val & INT_IDAUTH_FAIL) && retry_id < 5) { + idtp9220_retry_id_auth(di); + retry_id++; + dev_info(di->dev, "[idtp] id auth failed retry %d\n", retry); + goto out; + } else { + retry = 0; + retry_id = 0; + } + di->tx_charger_type = ADAPTER_AUTH_FAILED; + + schedule_delayed_work(&di->rx_vout_work, + msecs_to_jiffies(0)); + schedule_delayed_work(&di->chg_monitor_work, + msecs_to_jiffies(0)); + goto out; + } else + retry = 0; +/* + if (int_val & INT_IDAUTH_FAIL) { + idtp922x_request_adapter(di); + goto out; + } +*/ + + if (int_val & INT_SEND_TIMEOUT) { + if (retry_count < 3) { + dev_info(di->dev, "timeout retry %d\n", retry_count); + idtp922x_retry_cmd(di); + retry_count++; + goto out; + } else { + dev_err(di->dev, "%s: retry failed\n", __func__); + di->tx_charger_type = ADAPTER_AUTH_FAILED; + schedule_delayed_work(&di->rx_vout_work, + msecs_to_jiffies(0)); + schedule_delayed_work(&di->chg_monitor_work, + msecs_to_jiffies(0)); + retry_count = 0; + goto out; + } + } else { + retry_count = 0; + + } + + if (int_val & INT_TX_DATA_RECV) { + idtp922x_receivePkt(di, recive_data); + dev_info(di->dev, "[idt] cmd: %x\n", recive_data[0]); + + switch (recive_data[0]) { + case BC_TX_HWID: + if(recive_data[4] == 0x01 && + recive_data[2] == 0x2 && + recive_data[3] == 0x8 && + recive_data[1] == 0x6) + { + di->is_car_tx = 1; + } + idtp922x_request_adapter(di); + break; + case BC_TX_COMPATIBLE_HWID: + if(recive_data[1] == 0x12 && recive_data[2]) + di->is_compatible_hwid = 1; + if(recive_data[1] == 0x16 && recive_data[2] == 0x11) + di->is_f1_tx = 1; + idtp922x_request_adapter(di); + break; + case BC_ADAPTER_TYPE: + if (di->is_car_tx && (recive_data[1] == ADAPTER_XIAOMI_QC3)) + + di->tx_charger_type = ADAPTER_ZIMI_CAR_POWER; + else + di->tx_charger_type = recive_data[1]; + + if(!di->epp && (di->tx_charger_type == ADAPTER_QC3 || + di->tx_charger_type == ADAPTER_QC2)) { + idtp922x_set_adap_vol(di, ADAPTER_BPP_VOL); + } + schedule_delayed_work(&di->rx_vout_work, + msecs_to_jiffies(100)); + schedule_delayed_work(&di->chg_monitor_work, + msecs_to_jiffies(1000)); + if (di->wireless_psy) + power_supply_changed(di->wireless_psy); + break; + case BC_READ_Vin: + tx_vin = recive_data[1] | (recive_data[2] << 8); + if(!di->power_off_mode) { + if (di->epp) + idtp922x_set_adap_vol(di, ADAPTER_EPP_MI_VOL); + else + idtp922x_set_adap_vol(di, ADAPTER_BPP_QC_VOL); + } + break; + case BC_RX_ID_AUTH: + idtp9220_send_device_auth(di); + break; + default: + dev_info(di->dev, "[idt] unsupport cmd: %x\n", recive_data[0]); + break; + } + } + +out: + return; +} + +static irqreturn_t idtp9220_wpc_det_irq_handler(int irq, void *dev_id) +{ + struct idtp9220_device_info *di = dev_id; + + schedule_delayed_work(&di->wpc_det_work, msecs_to_jiffies(0)); + + return IRQ_HANDLED; +} + +static irqreturn_t idtp9220_irq_handler(int irq, void *dev_id) +{ + + struct idtp9220_device_info *di = dev_id; + + schedule_delayed_work(&di->irq_work, msecs_to_jiffies(30)); + + return IRQ_HANDLED; +} + +static int idtp9220_irq_request(struct idtp9220_device_info *di) +{ + int ret = 0; + + if (!di->irq) { + dev_err(di->dev, "%s: irq is wrong\n", __func__); + return -EINVAL; + } + + ret = request_irq(di->irq, idtp9220_irq_handler, + IRQF_TRIGGER_FALLING, di->name, di); + if (ret) { + dev_err(di->dev, "%s: request_irq failed\n", __func__); + return ret; + } + + ret = enable_irq_wake(di->irq); + if(ret) { + dev_err(di->dev, "%s: enable_irq_wake failed\n", __func__); + return ret; + } + + if (!di->wpc_irq) { + dev_err(di->dev, "%s: wpc irq is wrong\n", __func__); + return -EINVAL; + } + + ret = request_irq(di->wpc_irq, idtp9220_wpc_det_irq_handler, + IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "wpc_det", di); + if (ret) { + dev_err(di->dev, "%s: wpc request_irq failed\n", __func__); + return ret; + } + + ret = enable_irq_wake(di->wpc_irq); + if(ret) { + dev_err(di->dev, "%s: enable_irq_wake failed\n", __func__); + return ret; + } + + return 0; +} + + +static struct regmap_config i2c_idtp9220_regmap_config = { + .reg_bits = 16, + .val_bits = 8, + .max_register = 0xFFFF, +}; + +/* +static int idtp9220_get_version(struct idtp9220_device_info *di) +{ + int id_val = 0; + u8 chip_id[2] = {0}; + + di->bus.read_buf(di, REG_CHIP_ID_L, chip_id, 2); + id_val = (chip_id[1] << 8) | chip_id[0]; + + return id_val; +} +*/ + +static enum power_supply_property idtp9220_props[] = { + POWER_SUPPLY_PROP_PIN_ENABLED, + POWER_SUPPLY_PROP_PRESENT, + POWER_SUPPLY_PROP_WIRELESS_VERSION, + POWER_SUPPLY_PROP_SIGNAL_STRENGTH, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, + POWER_SUPPLY_PROP_TX_ADAPTER, +}; + +static int idtp9220_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct idtp9220_device_info *di = power_supply_get_drvdata(psy); + + switch (psp) { + case POWER_SUPPLY_PROP_PIN_ENABLED: + val->intval = gpio_get_value(di->dt_props.enable_gpio); + break; + case POWER_SUPPLY_PROP_PRESENT: + val->intval = di->dcin_present; + break; + case POWER_SUPPLY_PROP_WIRELESS_VERSION: + val->intval = di->epp; + break; + case POWER_SUPPLY_PROP_SIGNAL_STRENGTH: + val->intval = di->ss; + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + val->intval = idtp9220_get_vout_regulator(di); + break; + case POWER_SUPPLY_PROP_TX_ADAPTER: + val->intval = di->tx_charger_type; + break; + default: + return -EINVAL; + } + return 0; +} + +static int idtp9220_set_prop(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct idtp9220_device_info *di = power_supply_get_drvdata(psy); + int rc = 0; + + int data; + + switch (psp) { + case POWER_SUPPLY_PROP_PIN_ENABLED: + rc = idtp9220_set_enable_mode(di, val->intval); + break; + case POWER_SUPPLY_PROP_PRESENT: + rc = idtp9220_set_present(di, val->intval); + break; + case POWER_SUPPLY_PROP_SIGNAL_STRENGTH: + di->ss = val->intval; + power_supply_changed(di->idtp_psy); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + data = val->intval/1000; + if(data >= 6000) { + idtp9220_set_vout_regulator(di, data); + dev_info(di->dev, "[idt] set buck %s\n", __func__); + } + break; + default: + return -EINVAL; + } + + return rc; +} + +static int idtp9220_prop_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + int rc; + + switch (psp) { + case POWER_SUPPLY_PROP_PIN_ENABLED: + case POWER_SUPPLY_PROP_PRESENT: + case POWER_SUPPLY_PROP_SIGNAL_STRENGTH: + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + return 1; + default: + rc = 0; + break; + } + + return rc; +} + +static const struct power_supply_desc idtp_psy_desc = { + .name = "idt", + .type = POWER_SUPPLY_TYPE_WIRELESS, + .properties = idtp9220_props, + .num_properties = ARRAY_SIZE(idtp9220_props), + .get_property = idtp9220_get_prop, + .set_property = idtp9220_set_prop, + .property_is_writeable = idtp9220_prop_is_writeable, +}; + +static int idtp9220_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + int ret = 0; + struct idtp9220_device_info *di; + struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent); + struct power_supply_config idtp_cfg = {}; + + if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE)) { + dev_err(&client->dev, "i2c check functionality failed!\n"); + return -EIO; + } + + di = devm_kzalloc(&client->dev, sizeof(*di), GFP_KERNEL); + if (!di) { + dev_err(&client->dev, "i2c allocated device info data failed!\n"); + return -ENOMEM; + } + + di->name = IDT_DRIVER_NAME; + di->dev = &client->dev; + di->chip_enable = 1; + di->ss = 2; + di->status = NORMAL_MODE; + di->regmap = devm_regmap_init_i2c(client, &i2c_idtp9220_regmap_config); + if (!di->regmap) + return -ENODEV; + di->bus.read = idtp9220_read; + di->bus.write = idtp9220_write; + di->bus.read_buf = idtp9220_read_buffer; + di->bus.write_buf = idtp9220_write_buffer; + INIT_DELAYED_WORK(&di->irq_work, idtp9220_irq_work); + INIT_DELAYED_WORK(&di->wpc_det_work, idtp9220_wpc_det_work); + mutex_init(&di->read_lock); + mutex_init(&di->write_lock); + device_init_wakeup(&client->dev, true); + i2c_set_clientdata(client, di); + g_di = di; + + ret = idtp9220_parse_dt(di); + if (ret < 0) { + dev_err(di->dev, "%s: parse dt error [%d]\n", + __func__, ret); + goto cleanup; + } + + ret = idtp9220_gpio_init(di); + if (ret < 0) { + dev_err(di->dev, "%s: gpio init error [%d]\n", + __func__, ret); + goto cleanup; + } + + ret = idtp9220_irq_request(di); + if (ret < 0) { + dev_err(di->dev, "%s: request irq error [%d]\n", + __func__, ret); + goto cleanup; + } + + if(sysfs_create_group(&client->dev.kobj, &sysfs_group_attrs)) { + dev_err(&client->dev, "create sysfs attrs failed!\n"); + ret = -EIO; + goto cleanup; + } + idtp_cfg.drv_data = di; + di->idtp_psy = power_supply_register(di->dev, + &idtp_psy_desc, + &idtp_cfg); + + INIT_DELAYED_WORK(&di->chg_monitor_work,idtp9220_monitor_work); + INIT_DELAYED_WORK(&di->chg_detect_work,idtp9220_chg_detect_work); + INIT_DELAYED_WORK(&di->bpp_connect_load_work,idtp9220_bpp_connect_load_work); + INIT_DELAYED_WORK(&di->epp_connect_load_work,idtp9220_epp_connect_load_work); + INIT_DELAYED_WORK(&di->cmd_check_work,idtp9220_cmd_check_work); + INIT_DELAYED_WORK(&di->vout_regulator_work,idtp9220_vout_regulator_work); + INIT_DELAYED_WORK(&di->rx_vout_work,idtp9220_rx_vout_work); + INIT_DELAYED_WORK(&di->dc_check_work,idtp9220_dc_check_work); + INIT_DELAYED_WORK(&di->fast_operate_work,idtp9220_fast_operate_work); + INIT_DELAYED_WORK(&di->mophie_tx_work, idtp9220_mophie_tx_work); + INIT_DELAYED_WORK(&di->bpp_e5_tx_work, idtp9220_bpp_e5_tx_work); + INIT_DELAYED_WORK(&di->qc2_f1_tx_work, idtp9220_qc2_f1_tx_work); + INIT_DELAYED_WORK(&di->qc3_epp_work, idtp9220_qc3_epp_work); + + + dev_info(di->dev, "[idt] success probe idtp922x driver\n"); + schedule_delayed_work(&di->chg_detect_work, 3 * HZ); + + return 0; + +cleanup: + free_irq(di->irq, di); + cancel_delayed_work_sync(&di->irq_work); + i2c_set_clientdata(client, NULL); + + return ret; +} + +static int idtp9220_remove(struct i2c_client *client) +{ + struct idtp9220_device_info *di = i2c_get_clientdata(client); + + gpio_free(di->dt_props.enable_gpio); + cancel_delayed_work_sync(&di->irq_work); + i2c_set_clientdata(client, NULL); + + return 0; +} + +static void idtp9220_shutdown(struct i2c_client *client) +{ + struct idtp9220_device_info *di = i2c_get_clientdata(client); + + if (di->power_good_flag) + idtp9220_set_reset(di); +} + +static const struct i2c_device_id idtp9220_id[] = { + {IDT_DRIVER_NAME, 0}, + {}, +}; + +static const struct of_device_id idt_match_table[] = { + {.compatible = "idt,p9220"}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, idtp9220_id); + +static struct i2c_driver idtp9220_driver = { + .driver = { + .name = IDT_DRIVER_NAME, + .owner = THIS_MODULE, + .of_match_table = idt_match_table, + }, + .probe = idtp9220_probe, + .remove = idtp9220_remove, + .shutdown = idtp9220_shutdown, + .id_table = idtp9220_id, +}; + +module_i2c_driver(idtp9220_driver); + +MODULE_AUTHOR("bsp-charging@xiaomi.com"); +MODULE_DESCRIPTION("IDTP9220 Wireless Power Charger Monitor driver"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/power/supply/qcom/idtp9220.h b/drivers/power/supply/qcom/idtp9220.h new file mode 100644 index 000000000000..60cff62f4de7 --- /dev/null +++ b/drivers/power/supply/qcom/idtp9220.h @@ -0,0 +1,1266 @@ +/** + * @file idtp9220.h + * @author + * @date Sun Nov 22 11:49:55 2015 + * + * @brief + * + * + */ +#ifndef __IDTP9220_H__ +#define __IDTP9220_H__ + +#include +#include +#include + +#define IDT_DRIVER_NAME "idtp9220" +#define IDT_I2C_ADDR 0x61 + +#define HSCLK 60000 + +#define ADJUST_METE_MV 35 +#define IDTP9220_DELAY 2000 +#define CHARGING_FULL 100 +#define CHARGING_NEED 95 + +/* status low regiter bits define */ +#define STATUS_VOUT_ON (1 << 7) +#define STATUS_VOUT_OFF (1 << 6) +#define STATUS_TX_DATA_RECV (1 << 4) +#define STATUS_OV_TEMP (1 << 2) +#define STATUS_OV_VOL (1 << 1) +#define STATUS_OV_CURR (1 << 0) + +#define OVER_EVENT_OCCUR (STATUS_OV_TEMP | STATUS_OV_VOL | STATUS_OV_CURR) +#define TOGGLE_LDO_ON_OFF (1 << 1) + +/* interrupt register bits define */ +#define INT_IDAUTH_SUCESS (1 << 13) +#define INT_IDAUTH_FAIL (1 << 12) +#define INT_SEND_SUCESS (1 << 11) +#define INT_SEND_TIMEOUT (1 << 10) +#define INT_AUTH_SUCESS (1 << 9) +#define INT_AUTH_FAIL (1 << 8) +#define INT_VOUT_OFF (1 << 7) +#define INT_VOUT_ON (1 << 6) +#define INT_MODE_CHANGE (1 << 5) +#define INT_TX_DATA_RECV (1 << 4) +#define INT_VSWITCH_SUCESS (1 << 3) +#define INT_OV_TEMP (1 << 2) +#define INT_OV_VOL (1 << 1) +#define INT_OV_CURR (1 << 0) + +/* used registers define */ +#define REG_CHIP_ID_L 0x0000 +#define REG_CHIP_ID_H 0x0001 +#define REG_CHIP_REV 0x0002 +#define REG_CTM_ID 0x0003 +#define REG_OTPFWVER_ADDR 0x0004 // OTP firmware version +#define REG_EPRFWVER_ADDR 0x001c // EEPROM firmware version +#define REG_STATUS_L 0x0034 +#define REG_STATUS_H 0x0035 +#define REG_INTR_L 0x0036 +#define REG_INTR_H 0x0037 +#define REG_INTR_EN_L 0x0038 +#define REG_INTR_EN_H 0x0039 +#define REG_CHG_STATUS 0x003A +#define REG_ADC_VOUT_L 0x003C +#define REG_ADC_VOUT_H 0x003D +#define REG_VOUT_SET 0x003E +#define REG_VRECT_ADJ 0x003F +#define REG_ADC_VRECT 0x0040 +#define REG_RX_LOUT_L 0x0044 +#define REG_RX_LOUT_H 0x0045 +#define REG_FREQ_ADDR 0x0048 // Operating Frequency, Fop(KHz) = 64 * 6000 /value * 256) +#define REG_ILIM_SET 0x004A +#define REG_SIGNAL_STRENGTH 0x004B +#define REG_WPC_MODE 0x004D +#define REG_SSCMND 0x004e // Command Register, COM (0x4E) +#define REG_RX_RESET 0x004F +#define REG_PROPPKT 0x0050 // Proprietary Packet Header Register, PPP_Header (0x50) +#define REG_PPPDATA 0x0051 // PPP Data Value Register(0X51, 0x52, 0x53, 0x54, 0x55) +#define REG_SSINTCLR 0x0056 // Interrupt Clear Registers, INT_Clear_L (0x56) +#define REG_BCHEADER 0x0058 // Back Channel Packet Register (0x58) +#define REG_BCDATA 0x0059 // Back Channel Packet Register (0x59, 0x5A, 0x5B, 0x5C) +#define REG_FC_VOLTAGE_L 0x0078 // Fast Charging Voltage Register +#define REG_FC_VOLTAGE_H 0x0079 +#define REG_REGULATOR_L 0x000C +#define REG_REGULATOR_H 0x000d +#define REG_POWER_MAX 0x0084 //Get the TX power on EPP mode. +#define REG_TX_TYPE 0x00A2 //Get the TX type. + +// RX -> TX +#define PROPRIETARY18 0x18 +#define PROPRIETARY28 0x28 +#define PROPRIETARY38 0x38 +#define PROPRIETARY48 0x48 +#define PROPRIETARY58 0x58 + +// bitmap for customer command +#define BC_NONE 0x00 +#define BC_SET_FREQ 0x03 +#define BC_GET_FREQ 0x04 +#define BC_READ_FW_VER 0x05 +#define BC_READ_Iin 0x06 +#define BC_READ_Vin 0x07 +#define BC_SET_Vin 0x0a + +#define BC_ADAPTER_TYPE 0x0b +#define BC_RESET 0x0c +#define BC_READ_I2C 0x0d +#define BC_WRITE_I2C 0x0e +#define BC_VI2C_INIT 0x10 +#define BC_RX_ID_AUTH 0x3b +#define BC_TX_COMPATIBLE_HWID 0x3f +#define BC_TX_HWID 0x4c +#define BC_TX_TOGGLE 0xc4 + +//Factory test command +#define BC_READ_IOUT 0x12 +#define BC_READ_VOUT 0x13 +#define BC_START_CHARGE 0x30 +#define BC_SET_AP_OVERLOAD 0x31 +#define BC_ENABLE_FAST_CHARGE 0x32 + +/* Adapter_list = {0x00:'ADAPTER_UNKNOWN', */ +/* 0x01:'SDP 500mA', */ +/* 0x02:'CDP 1.1A', */ +/* 0x03:'DCP 1.5A', */ +/* 0x05:'QC2.0', */ +/* 0x06:'QC3.0', */ +/* 0x07:'PD',} */ +//define adapter type +#define ADAPTER_NONE 0x00 +#define ADAPTER_SDP 0x01 +#define ADAPTER_CDP 0x02 +#define ADAPTER_DCP 0x03 +#define ADAPTER_QC2 0x05 +#define ADAPTER_QC3 0x06 +#define ADAPTER_PD 0x07 +#define ADAPTER_AUTH_FAILED 0x08 +#define ADAPTER_XIAOMI_QC3 0x09 +#define ADAPTER_XIAOMI_PD 0x0a +#define ADAPTER_ZIMI_CAR_POWER 0x0b +#define ADAPTER_XIAOMI_PD_40W 0x0c + +#define NORMAL_MODE 0x1 +#define TAPER_MODE 0x2 +#define FULL_MODE 0x3 +#define RECHG_MODE 0x4 + +// bitmap for status flags +// 1: indicates a pending interrupt for LDO Vout state change – from OFF to ON +#define VOUTCHANGED BIT(7) // Stat_Vout_ON +// 1: indicates a pending interrupt for TX Data Received. (Change from “No Received Data” state to “Data Received” state) +#define TXDATARCVD BIT(4) // TX Data Received + +// bitmap for SSCmnd register 0x4e +#define VSWITCH BIT(7) +// If AP sets this bit to "1" then IDTP9220 M0 clears the interrupt corresponding to the bit(s) which has a value of “1” +#define CLRINT BIT(5) // Clear Interrupt +// If AP sets this bit to "1" then IDTP9220 M0 toggles LDO output once (from on to off, or from off to on), and then sets this bit to “0” +#define LDOTGL BIT(1) // Toggle LDO On/OFF +// If AP sets this bit to “1” then IDTP9220 M0 sends the Proprietary Packet +#define SENDPROPP BIT(0) // SEND RX Data + +#define SEND_DEVICE_AUTH BIT(2) + +enum VOUT_SET_VAL { + VOUT_VAL_3500_MV = 0, + VOUT_VAL_3600_MV, + VOUT_VAL_3700_MV, + VOUT_VAL_3800_MV, + VOUT_VAL_3900_MV, + VOUT_VAL_4000_MV, + VOUT_VAL_4100_MV, + VOUT_VAL_4200_MV, + VOUT_VAL_4300_MV, + VOUT_VAL_4400_MV, + VOUT_VAL_4500_MV, + VOUT_VAL_4600_MV, + VOUT_VAL_4700_MV, + VOUT_VAL_4800_MV, + VOUT_VAL_4900_MV, + VOUT_VAL_5000_MV, + VOUT_VAL_5100_MV, + VOUT_VAL_5200_MV, + VOUT_VAL_5300_MV, + VOUT_VAL_5400_MV, + VOUT_VAL_5500_MV, + VOUT_VAL_5600_MV, + VOUT_VAL_5700_MV, + VOUT_VAL_5800_MV, + VOUT_VAL_5900_MV, + VOUT_VAL_6000_MV, + VOUT_VAL_6100_MV, + VOUT_VAL_6200_MV, + VOUT_VAL_6300_MV, + VOUT_VAL_6400_MV, + VOUT_VAL_6500_MV, + VOUT_VAL_6600_MV, + VOUT_VAL_6700_MV, + VOUT_VAL_6800_MV, + VOUT_VAL_6900_MV, + VOUT_VAL_7000_MV, + VOUT_VAL_7100_MV, + VOUT_VAL_7200_MV, + VOUT_VAL_7300_MV, + VOUT_VAL_7400_MV, + VOUT_VAL_7500_MV, + VOUT_VAL_7600_MV, + VOUT_VAL_7700_MV, + VOUT_VAL_7800_MV, + VOUT_VAL_7900_MV, + VOUT_VAL_8000_MV, +}; + +enum IMIL_SET_VAL { + CURR_VAL_100_MA = 0, + CURR_VAL_200_MA, + CURR_VAL_300_MA, + CURR_VAL_400_MA, + CURR_VAL_500_MA, + CURR_VAL_600_MA, + CURR_VAL_700_MA, + CURR_VAL_800_MA, + CURR_VAL_900_MA, + CURR_VAL_1000_MA, + CURR_VAL_1100_MA, + CURR_VAL_1200_MA, + CURR_VAL_1300_MA, +}; + +struct vol_curr_table { + int index; + char *val; +}; +/* +struct idtp9220_platform_data { + enum VOUT_SET_VAL vout_val_default; + enum IMIL_SET_VAL curr_val_default; + unsigned long gpio_en; +}; +*/ +typedef struct { // write to structure at SRAM address 0x0400 + u16 status; // Read/Write by both 9220 and 9220 host + u16 startAddr; // OTP image address of the current packet + u16 codeLength; // The size of the OTP image data in the current packet + u16 dataChksum; // Checksum of the current packet + u8 dataBuf[128]; // OTP image data of the current packet +}idtp9220_packet_t; + +// proprietary packet type +typedef struct { + u8 header; // The header consists of a single byte that indicates the Packet type. + u8 cmd; // Back channel command + u8 data[4]; // Send data buffer +} ProPkt_Type; + +#if 1 +static char bootloader_data[] = { + 0x00, 0x04, 0x00, 0x20, 0xe3, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, /// 0x10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, /// 0x30 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x41, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x40 + 0xfe, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x3e, 0x49, 0x00, 0x20, 0x0a, 0x88, 0x05, 0x46, 0x93, 0x06, /// 0x50 + 0x00, 0xd5, 0x04, 0x20, 0xd2, 0x06, 0x07, 0xd5, 0x8a, 0x78, 0x0b, 0x79, 0x1a, 0x43, 0x92, 0x07, /// 0x60 + 0x02, 0xd1, 0x20, 0x22, 0x10, 0x43, 0x01, 0x25, 0x36, 0x4b, 0x5a, 0x22, 0x1a, 0x74, 0x35, 0x4b, /// 0x70 + 0x20, 0x3b, 0x18, 0x72, 0x02, 0x20, 0x40, 0x1c, 0x20, 0x28, 0xfc, 0xd3, 0x32, 0x4c, 0x00, 0x26, /// 0x80 + 0xa6, 0x81, 0x48, 0x88, 0xe2, 0x13, 0x82, 0x18, 0x00, 0x2d, 0x09, 0xd0, 0x00, 0x20, 0x03, 0xe0, /// 0x90 + 0x45, 0x18, 0xad, 0x68, 0x15, 0x50, 0x00, 0x1d, 0x8d, 0x88, 0x85, 0x42, 0xf8, 0xd8, 0x08, 0xe0, /// 0xa0 + 0x00, 0x20, 0x03, 0xe0, 0x45, 0x18, 0x2d, 0x7a, 0x15, 0x54, 0x40, 0x1c, 0x8d, 0x88, 0x85, 0x42, /// 0xb0 + 0xf8, 0xd8, 0x1e, 0x72, 0x25, 0x48, 0xa0, 0x81, 0x02, 0x20, 0x00, 0x24, 0x23, 0x46, 0x0b, 0xe0, /// 0xc0 + 0x5f, 0x18, 0x3e, 0x7a, 0xd5, 0x5c, 0xae, 0x42, 0x05, 0xd0, 0x3d, 0x72, 0x00, 0x2c, 0x00, 0xd1, /// 0xd0 + 0x4b, 0x80, 0x04, 0x20, 0x64, 0x1c, 0x5b, 0x1c, 0x8d, 0x88, 0x9d, 0x42, 0xf0, 0xd8, 0x8c, 0x80, /// 0xe0 + 0xf0, 0xbd, 0x1c, 0x49, 0x1a, 0x48, 0x08, 0x60, 0x17, 0x48, 0x5a, 0x21, 0x40, 0x38, 0x01, 0x70, /// 0xf0 + 0x01, 0x21, 0x01, 0x71, 0x05, 0x21, 0x01, 0x72, 0x17, 0x49, 0x81, 0x81, 0x08, 0x25, 0x10, 0x4f, /// 0x100 + 0x02, 0x26, 0x38, 0x78, 0x3c, 0x46, 0xc0, 0x07, 0xfb, 0xd0, 0x60, 0x88, 0xa2, 0x88, 0x10, 0x18, /// 0x110 + 0x81, 0xb2, 0x00, 0x20, 0x04, 0xe0, 0x03, 0x19, 0x1b, 0x7a, 0x59, 0x18, 0x89, 0xb2, 0x40, 0x1c, /// 0x120 + 0x82, 0x42, 0xf8, 0xd8, 0xe0, 0x88, 0x88, 0x42, 0x01, 0xd0, 0x3d, 0x80, 0xe9, 0xe7, 0x00, 0x2a, /// 0x130 + 0x03, 0xd0, 0xff, 0xf7, 0x87, 0xff, 0x20, 0x80, 0xe3, 0xe7, 0x3e, 0x80, 0xe1, 0xe7, 0x00, 0x00, /// 0x140 + 0x00, 0x04, 0x00, 0x20, 0x40, 0x5c, 0x00, 0x40, 0x40, 0x30, 0x00, 0x40, 0xff, 0x01, 0x00, 0x00, /// 0x150 + 0xff, 0x0f, 0x00, 0x00, 0x80, 0xe1, 0x00, 0xe0, 0x04, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; + +unsigned char idt_firmware_otp[] = { /// ver 2.3.1.42 + 0x00, 0x08, 0x00, 0x20, 0xa9, 0x02, 0x00, 0x00, 0x71, 0x00, 0x00, 0x00, 0x73, 0x00, 0x00, 0x00, /// 0x10 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x20 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x75, 0x00, 0x00, 0x00, /// 0x30 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x40 + 0x81, 0x0e, 0x00, 0x00, 0x87, 0x0e, 0x00, 0x00, 0x8d, 0x0e, 0x00, 0x00, 0x93, 0x0e, 0x00, 0x00, /// 0x50 + 0x99, 0x0e, 0x00, 0x00, 0x9f, 0x0e, 0x00, 0x00, 0xa5, 0x0e, 0x00, 0x00, 0xab, 0x0e, 0x00, 0x00, /// 0x60 + 0xb1, 0x0e, 0x00, 0x00, 0xb7, 0x0e, 0x00, 0x00, 0xbd, 0x0e, 0x00, 0x00, 0xc3, 0x0e, 0x00, 0x00, /// 0x70 + 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0xfe, 0xe7, 0x00, 0x20, 0x00, 0x68, 0x80, 0xf3, /// 0x80 + 0x08, 0x88, 0x70, 0x47, 0xb6, 0x48, 0x00, 0x21, 0x01, 0x72, 0x41, 0x72, 0x70, 0x47, 0x10, 0xb5, /// 0x90 + 0xb3, 0x4b, 0x1a, 0x7a, 0x5c, 0x7a, 0x51, 0x1c, 0x09, 0x07, 0x09, 0x0f, 0x8c, 0x42, 0x01, 0xd1, /// 0xa0 + 0x01, 0x20, 0x10, 0xbd, 0xaf, 0x4c, 0x92, 0x00, 0x12, 0x19, 0xff, 0x32, 0x01, 0x32, 0x90, 0x60, /// 0xb0 + 0x19, 0x72, 0x00, 0x20, 0x10, 0xbd, 0xab, 0x4e, 0x34, 0x46, 0xff, 0x34, 0x41, 0x34, 0x21, 0x7a, /// 0xc0 + 0x60, 0x7a, 0x81, 0x42, 0x01, 0xd1, 0x30, 0xbf, 0xf9, 0xe7, 0x81, 0x00, 0x89, 0x19, 0xff, 0x31, /// 0xd0 + 0x01, 0x31, 0x8d, 0x68, 0x00, 0x2d, 0x0c, 0xd0, 0x40, 0x1c, 0x00, 0x07, 0x00, 0x0f, 0x60, 0x72, /// 0xe0 + 0xa8, 0x47, 0x00, 0x28, 0xeb, 0xd0, 0x72, 0xb6, 0x28, 0x46, 0xff, 0xf7, 0xd0, 0xff, 0x62, 0xb6, /// 0xf0 + 0xe5, 0xe7, 0xff, 0xf7, 0xc7, 0xff, 0xe2, 0xe7, 0x9c, 0x49, 0x9b, 0x48, 0x08, 0x60, 0xff, 0xf7, /// 0x100 + 0xbc, 0xff, 0x9b, 0x48, 0x5a, 0x21, 0x01, 0x70, 0x00, 0x24, 0x04, 0x71, 0x09, 0x21, 0x01, 0x72, /// 0x110 + 0x98, 0x49, 0x81, 0x81, 0x0a, 0x21, 0x81, 0x82, 0x97, 0x49, 0x01, 0x83, 0x08, 0x21, 0x81, 0x83, /// 0x120 + 0x93, 0x49, 0x02, 0x20, 0x20, 0x31, 0x08, 0x76, 0x94, 0x48, 0x84, 0x80, 0x93, 0x49, 0x94, 0x48, /// 0x130 + 0x08, 0x80, 0x39, 0x20, 0x00, 0x02, 0x08, 0x82, 0x92, 0x48, 0x01, 0x26, 0x06, 0x80, 0x81, 0x27, /// 0x140 + 0x07, 0x80, 0x90, 0x48, 0x90, 0x49, 0x20, 0x30, 0x01, 0x80, 0x90, 0x49, 0x89, 0x78, 0x31, 0x43, /// 0x150 + 0x01, 0x71, 0x8f, 0x49, 0x40, 0x20, 0x08, 0x72, 0x20, 0x20, 0x08, 0x76, 0x0c, 0x77, 0x8c, 0x49, /// 0x160 + 0x20, 0x31, 0x08, 0x70, 0x0c, 0x71, 0x08, 0x73, 0x08, 0x74, 0x8a, 0x48, 0x81, 0xb2, 0x8a, 0x48, /// 0x170 + 0x00, 0xf0, 0xff, 0xfb, 0x30, 0x22, 0x89, 0x49, 0x89, 0x48, 0x00, 0xf0, 0xea, 0xfb, 0x89, 0x4d, /// 0x180 + 0x0e, 0x20, 0xa8, 0x72, 0x07, 0x20, 0xe8, 0x73, 0x4b, 0x20, 0x00, 0x01, 0x00, 0xf0, 0xdc, 0xfb, /// 0x190 + 0x85, 0x48, 0x06, 0x70, 0x07, 0x70, 0x84, 0x49, 0x3b, 0x20, 0x08, 0x71, 0x3f, 0x20, 0x08, 0x81, /// 0x1a0 + 0x21, 0x20, 0x08, 0x70, 0x00, 0xf0, 0xec, 0xfb, 0x00, 0xf0, 0x6f, 0xfb, 0x7f, 0x49, 0x06, 0x20, /// 0x1b0 + 0x08, 0x60, 0x6e, 0x49, 0x80, 0x39, 0x08, 0x60, 0x7d, 0x48, 0x06, 0x80, 0x03, 0x21, 0x01, 0x80, /// 0x1c0 + 0x41, 0x21, 0x01, 0x76, 0x7b, 0x48, 0x00, 0xf0, 0x55, 0xf9, 0x7b, 0x48, 0x04, 0x71, 0x7b, 0x48, /// 0x1d0 + 0x44, 0x70, 0x00, 0xf0, 0xd1, 0xfd, 0x2f, 0x46, 0x60, 0x3f, 0x78, 0x73, 0x00, 0xf0, 0xe7, 0xfa, /// 0x1e0 + 0x75, 0x48, 0x01, 0x7a, 0x89, 0x07, 0xfc, 0xd5, 0x73, 0x49, 0x20, 0x31, 0x0c, 0x70, 0x02, 0x21, /// 0x1f0 + 0x01, 0x72, 0x5b, 0x49, 0x10, 0x22, 0x4c, 0x31, 0x88, 0x18, 0x00, 0xf0, 0xaa, 0xfb, 0x07, 0x22, /// 0x200 + 0x01, 0x21, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x40, 0x03, 0x01, 0x0c, 0x65, 0x48, 0x20, 0x38, /// 0x210 + 0x81, 0x85, 0x78, 0x7b, 0xc0, 0x07, 0x0d, 0xd0, 0x61, 0x48, 0x69, 0x49, 0x81, 0x61, 0x48, 0x20, /// 0x220 + 0xe8, 0x72, 0x00, 0xf0, 0xab, 0xfa, 0x01, 0xf0, 0x07, 0xf9, 0x4d, 0x48, 0x44, 0x30, 0x00, 0xf0, /// 0x230 + 0x21, 0xf9, 0x01, 0xe0, 0x00, 0xf0, 0xe8, 0xfa, 0x62, 0x48, 0x01, 0x7d, 0x59, 0x4e, 0xa0, 0x3e, /// 0x240 + 0x31, 0x70, 0x01, 0x7c, 0x71, 0x70, 0x00, 0x7e, 0xb0, 0x70, 0x02, 0x20, 0xf0, 0x70, 0xff, 0x20, /// 0x250 + 0x02, 0x30, 0x70, 0x60, 0x5c, 0x48, 0xf0, 0x61, 0x0d, 0x20, 0xb8, 0x72, 0x30, 0x46, 0x01, 0x27, /// 0x260 + 0x60, 0x30, 0x87, 0x70, 0x00, 0xf0, 0xa8, 0xfd, 0xa8, 0x73, 0x00, 0xf0, 0x51, 0xf9, 0x57, 0x48, /// 0x270 + 0x07, 0x70, 0x81, 0x21, 0x01, 0x70, 0x0d, 0x21, 0x01, 0x70, 0x54, 0x4a, 0x95, 0x21, 0x20, 0x32, /// 0x280 + 0x11, 0x80, 0xff, 0x21, 0x81, 0x82, 0x03, 0x21, 0x09, 0x02, 0x01, 0x82, 0x04, 0x71, 0x47, 0x49, /// 0x290 + 0x61, 0x20, 0x08, 0x60, 0x35, 0x49, 0x80, 0x39, 0x08, 0x60, 0x4d, 0x48, 0x30, 0x87, 0x40, 0x48, /// 0x2a0 + 0x4c, 0x49, 0x41, 0x60, 0xff, 0xf7, 0x07, 0xff, 0x08, 0x20, 0x00, 0xf0, 0x4d, 0xfb, 0x30, 0x48, /// 0x2b0 + 0x40, 0x30, 0x01, 0x78, 0x49, 0x06, 0xfc, 0xd4, 0xff, 0xf7, 0x1e, 0xff, 0x30, 0xb5, 0x28, 0x4c, /// 0x2c0 + 0x38, 0x4d, 0x40, 0x3c, 0x20, 0x68, 0x40, 0x1c, 0x20, 0x3d, 0x20, 0x60, 0x28, 0x78, 0x80, 0x07, /// 0x2d0 + 0x04, 0xd4, 0x72, 0xb6, 0x60, 0x68, 0xff, 0xf7, 0xda, 0xfe, 0x62, 0xb6, 0x28, 0x78, 0x40, 0x07, /// 0x2e0 + 0x0a, 0xd5, 0x1f, 0x48, 0x20, 0x30, 0x81, 0x7d, 0xc0, 0x7d, 0x81, 0x42, 0x04, 0xd0, 0x72, 0xb6, /// 0x2f0 + 0x39, 0x48, 0xff, 0xf7, 0xcc, 0xfe, 0x62, 0xb6, 0x72, 0xb6, 0xa0, 0x6f, 0xff, 0xf7, 0xc7, 0xfe, /// 0x300 + 0x62, 0xb6, 0x00, 0x20, 0x30, 0xbd, 0x70, 0xb5, 0x00, 0x25, 0x27, 0x4c, 0x08, 0x26, 0x0a, 0xe0, /// 0x310 + 0x20, 0x78, 0x30, 0x43, 0x20, 0x70, 0x6d, 0x1c, 0x0a, 0x2d, 0x01, 0xd3, 0xff, 0xf7, 0xec, 0xfe, /// 0x320 + 0x14, 0x20, 0x00, 0xf0, 0x11, 0xfb, 0x20, 0x78, 0x00, 0x07, 0xf1, 0xd4, 0x15, 0x48, 0x20, 0x30, /// 0x330 + 0x01, 0x88, 0xc9, 0x04, 0x11, 0xd5, 0x0a, 0x49, 0x40, 0x39, 0x0a, 0x68, 0x80, 0x31, 0x09, 0x6e, /// 0x340 + 0x51, 0x1a, 0x02, 0x15, 0x91, 0x42, 0x08, 0xdb, 0x01, 0x88, 0x82, 0x14, 0x91, 0x43, 0x01, 0x80, /// 0x350 + 0x07, 0x48, 0x01, 0x8b, 0x42, 0x14, 0x91, 0x43, 0x01, 0x83, 0x00, 0x20, 0x70, 0xbd, 0x00, 0x00, /// 0x360 + 0x70, 0x02, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, 0xff, 0x0f, 0x00, 0x00, 0x80, 0xe1, 0x00, 0xe0, /// 0x370 + 0x00, 0x30, 0x00, 0x40, 0x05, 0x1d, 0x00, 0x00, 0x3b, 0x23, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, /// 0x380 + 0x01, 0x0a, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40, 0x0e, 0x30, 0x00, 0x00, 0x60, 0x47, 0x00, 0x00, /// 0x390 + 0x00, 0x6c, 0x00, 0x40, 0xc8, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0xe4, 0x14, 0x00, 0x00, /// 0x3a0 + 0x00, 0x01, 0x00, 0x20, 0xa0, 0x00, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x40, 0x80, 0xe2, 0x00, 0xe0, /// 0x3b0 + 0x00, 0x44, 0x00, 0x40, 0xdc, 0x14, 0x00, 0x00, 0x00, 0x60, 0x00, 0x40, 0x70, 0x03, 0x00, 0x20, /// 0x3c0 + 0xff, 0x0f, 0x00, 0x00, 0x60, 0x58, 0x00, 0x40, 0x46, 0x01, 0x03, 0x02, 0x00, 0x64, 0x00, 0x40, /// 0x3d0 + 0x07, 0x40, 0x00, 0x00, 0x71, 0x10, 0x00, 0x00, 0x0d, 0x0e, 0x00, 0x00, 0x70, 0xb5, 0xf7, 0x49, /// 0x3e0 + 0x8a, 0x88, 0xd2, 0x43, 0x92, 0x07, 0x06, 0xd0, 0xf5, 0x4a, 0x92, 0x7f, 0x32, 0x2a, 0x02, 0xd3, /// 0x3f0 + 0x40, 0x09, 0x00, 0x23, 0x03, 0xe0, 0xc2, 0x00, 0x10, 0x1a, 0xc0, 0x09, 0x01, 0x23, 0x3c, 0x28, /// 0x400 + 0x01, 0xd2, 0x3c, 0x20, 0x02, 0xe0, 0xff, 0x28, 0x00, 0xd9, 0xff, 0x20, 0x0a, 0x8a, 0xed, 0x4c, /// 0x410 + 0x12, 0x0a, 0xc0, 0x1e, 0x82, 0x42, 0x15, 0xd0, 0x00, 0x2b, 0x02, 0xd1, 0x25, 0x79, 0x01, 0x2d, /// 0x420 + 0x03, 0xd0, 0x55, 0x1d, 0xa8, 0x42, 0x00, 0xd9, 0x28, 0x46, 0x0a, 0x8a, 0x40, 0x25, 0x2a, 0x43, /// 0x430 + 0x0a, 0x82, 0x0a, 0x8a, 0x4f, 0x26, 0x32, 0x40, 0x00, 0x02, 0x02, 0x43, 0x0a, 0x82, 0x08, 0x8a, /// 0x440 + 0xa8, 0x43, 0x08, 0x82, 0x23, 0x71, 0x70, 0xbd, 0x70, 0xb5, 0x00, 0x23, 0xde, 0x4d, 0x0b, 0xe0, /// 0x450 + 0x44, 0x00, 0x64, 0x19, 0xff, 0x34, 0x81, 0x34, 0xa4, 0x8b, 0x26, 0x0b, 0x96, 0x42, 0x07, 0xd1, /// 0x460 + 0x24, 0x05, 0x24, 0x0d, 0xe3, 0x18, 0x40, 0x18, 0x08, 0x28, 0xf1, 0xd3, 0x18, 0x46, 0x70, 0xbd, /// 0x470 + 0xd6, 0x48, 0x70, 0xbd, 0x10, 0xb5, 0xd6, 0x4a, 0x00, 0x21, 0x11, 0x70, 0xd1, 0x4b, 0x01, 0x21, /// 0x480 + 0x40, 0x3b, 0x59, 0x70, 0xd3, 0x49, 0x03, 0x88, 0x8b, 0x80, 0x43, 0x88, 0x0b, 0x81, 0x83, 0x88, /// 0x490 + 0x8b, 0x81, 0xc0, 0x88, 0x08, 0x82, 0xb4, 0x20, 0x10, 0x70, 0xca, 0x48, 0xf4, 0x38, 0x10, 0x81, /// 0x4a0 + 0x07, 0x20, 0x90, 0x80, 0xca, 0x48, 0x02, 0x22, 0x20, 0x38, 0x02, 0x72, 0x03, 0x79, 0x72, 0xb6, /// 0x4b0 + 0x13, 0x43, 0x03, 0x71, 0x62, 0xb6, 0x11, 0x20, 0x08, 0x80, 0x10, 0xbd, 0x01, 0x88, 0x42, 0x88, /// 0x4c0 + 0x51, 0x18, 0x82, 0x88, 0xc0, 0x88, 0x51, 0x18, 0x40, 0x18, 0xc3, 0x49, 0x00, 0x22, 0x8a, 0x5e, /// 0x4d0 + 0x80, 0x10, 0x80, 0x1a, 0x00, 0xd5, 0x00, 0x20, 0x70, 0x47, 0xc0, 0x49, 0x4a, 0x14, 0x0b, 0x8b, /// 0x4e0 + 0x00, 0x28, 0x05, 0xd0, 0x93, 0x43, 0x0b, 0x83, 0x03, 0x28, 0x03, 0xd9, 0x00, 0x22, 0x07, 0xe0, /// 0x4f0 + 0x13, 0x43, 0x0b, 0x83, 0x03, 0x21, 0x48, 0x40, 0x01, 0x21, 0x40, 0x03, 0x09, 0x03, 0x42, 0x18, /// 0x500 + 0xb7, 0x48, 0x01, 0x88, 0x07, 0x23, 0x1b, 0x03, 0x99, 0x43, 0x11, 0x43, 0x01, 0x80, 0x70, 0x47, /// 0x510 + 0xf8, 0xb5, 0xb2, 0x48, 0x00, 0x8b, 0x47, 0x26, 0xc0, 0x04, 0x36, 0x02, 0xc1, 0x0e, 0xb5, 0x8a, /// 0x520 + 0x30, 0x8b, 0x4f, 0x1c, 0x2c, 0x1a, 0xaf, 0x48, 0x21, 0x46, 0x78, 0x43, 0x00, 0xf0, 0x9e, 0xff, /// 0x530 + 0xa4, 0x49, 0xc8, 0x22, 0x40, 0x39, 0x00, 0x91, 0x88, 0x87, 0x28, 0x46, 0x21, 0x46, 0x50, 0x43, /// 0x540 + 0x00, 0xf0, 0xaa, 0xff, 0xff, 0x21, 0x91, 0x31, 0x08, 0x1a, 0x00, 0x99, 0xc8, 0x87, 0xf5, 0x8b, /// 0x550 + 0xf0, 0x8a, 0x29, 0x1a, 0xa4, 0x48, 0x78, 0x43, 0x00, 0xf0, 0x88, 0xff, 0x99, 0x4c, 0x80, 0xb2, /// 0x560 + 0x20, 0x80, 0x39, 0x46, 0x15, 0x22, 0x68, 0x43, 0x51, 0x43, 0x00, 0xf0, 0x7f, 0xff, 0x19, 0x21, /// 0x570 + 0x80, 0x09, 0x49, 0x01, 0x08, 0x1a, 0x00, 0xb2, 0x8d, 0x21, 0x48, 0x43, 0xc1, 0x17, 0x09, 0x0e, /// 0x580 + 0x08, 0x18, 0x00, 0x12, 0x60, 0x80, 0xf8, 0xbd, 0x70, 0xb5, 0x05, 0x46, 0x93, 0x48, 0x00, 0x8b, /// 0x590 + 0x8c, 0x4c, 0xc0, 0x04, 0x40, 0x3c, 0x61, 0x7a, 0xc0, 0x0e, 0x81, 0x42, 0x02, 0xd0, 0x60, 0x72, /// 0x5a0 + 0xff, 0xf7, 0xb6, 0xff, 0x91, 0x48, 0x85, 0x42, 0x03, 0xd8, 0x3e, 0x22, 0xa1, 0x8f, 0xa2, 0x5e, /// 0x5b0 + 0x1f, 0xe0, 0x8e, 0x49, 0x83, 0x48, 0x40, 0x31, 0x8d, 0x42, 0x03, 0xd3, 0x02, 0x22, 0x01, 0x88, /// 0x5c0 + 0x82, 0x5e, 0x16, 0xe0, 0x89, 0x49, 0xa3, 0x8f, 0x49, 0x42, 0x6a, 0x18, 0x01, 0x88, 0xc9, 0x1a, /// 0x5d0 + 0x51, 0x43, 0xce, 0x17, 0xb6, 0x0e, 0x71, 0x18, 0x89, 0x11, 0xc9, 0x18, 0x02, 0x26, 0x3e, 0x23, /// 0x5e0 + 0x86, 0x5f, 0xe3, 0x5e, 0xf0, 0x1a, 0x50, 0x43, 0xc2, 0x17, 0x92, 0x0e, 0x10, 0x18, 0x80, 0x11, /// 0x5f0 + 0xc2, 0x18, 0x4d, 0x43, 0x28, 0x0c, 0x80, 0x18, 0x00, 0xd5, 0x00, 0x20, 0x70, 0xbd, 0xf8, 0xb5, /// 0x600 + 0x02, 0x22, 0x04, 0x21, 0x00, 0x20, 0xff, 0xf7, 0x1f, 0xff, 0x6e, 0x4d, 0x6e, 0x4e, 0x20, 0x3d, /// 0x610 + 0xa9, 0x79, 0x09, 0x27, 0x49, 0x00, 0xc0, 0x03, 0x89, 0x19, 0xbf, 0x01, 0x00, 0x0c, 0xc9, 0x19, /// 0x620 + 0x88, 0x81, 0x01, 0x22, 0x04, 0x21, 0x10, 0x46, 0xff, 0xf7, 0x0e, 0xff, 0xa9, 0x79, 0xc0, 0x03, /// 0x630 + 0x49, 0x00, 0x89, 0x19, 0x00, 0x0c, 0xc9, 0x19, 0x88, 0x83, 0x03, 0x22, 0x08, 0x21, 0x10, 0x46, /// 0x640 + 0xff, 0xf7, 0x02, 0xff, 0xa9, 0x79, 0x0f, 0x22, 0x49, 0x00, 0x89, 0x19, 0xc9, 0x19, 0x88, 0x82, /// 0x650 + 0x04, 0x21, 0x02, 0x20, 0xff, 0xf7, 0xf8, 0xfe, 0xc0, 0x03, 0x01, 0x0c, 0xa8, 0x79, 0x40, 0x00, /// 0x660 + 0x82, 0x19, 0x05, 0x20, 0xc0, 0x01, 0x10, 0x18, 0x81, 0x81, 0x04, 0x22, 0x08, 0x21, 0x07, 0x20, /// 0x670 + 0xff, 0xf7, 0xea, 0xfe, 0x52, 0x4c, 0x20, 0x34, 0x23, 0x46, 0xe0, 0x80, 0x40, 0x3b, 0x98, 0x69, /// 0x680 + 0x41, 0x00, 0x58, 0x69, 0xc2, 0x0f, 0x11, 0x43, 0x99, 0x61, 0x41, 0x00, 0xa8, 0x79, 0x42, 0x00, /// 0x690 + 0x92, 0x19, 0xd2, 0x19, 0x12, 0x7b, 0x40, 0x1c, 0xd2, 0x07, 0xd2, 0x0f, 0x11, 0x43, 0x80, 0x07, /// 0x6a0 + 0x80, 0x0f, 0x59, 0x61, 0xa8, 0x71, 0x28, 0x46, 0x14, 0x38, 0xff, 0xf7, 0x07, 0xff, 0x21, 0x46, /// 0x6b0 + 0x60, 0x31, 0x0e, 0x22, 0x8a, 0x56, 0x80, 0x18, 0x20, 0x80, 0x28, 0x1f, 0xff, 0xf7, 0xfe, 0xfe, /// 0x6c0 + 0x60, 0x87, 0x28, 0x46, 0x0c, 0x38, 0xff, 0xf7, 0xf9, 0xfe, 0x98, 0x87, 0x28, 0x46, 0x2c, 0x30, /// 0x6d0 + 0xff, 0xf7, 0xf4, 0xfe, 0x40, 0x08, 0x01, 0x01, 0x40, 0x18, 0x27, 0x46, 0x58, 0x81, 0x40, 0x37, /// 0x6e0 + 0x38, 0x78, 0xc0, 0x06, 0x48, 0xd5, 0x60, 0x8f, 0xff, 0xf7, 0x4e, 0xff, 0xa1, 0x88, 0x08, 0x1a, /// 0x6f0 + 0x00, 0xd5, 0x40, 0x42, 0xc8, 0x28, 0x3f, 0xdd, 0xa8, 0x79, 0x40, 0x1e, 0x80, 0x07, 0x40, 0x0f, /// 0x700 + 0x81, 0x19, 0x09, 0x20, 0x80, 0x01, 0x08, 0x18, 0x2e, 0x49, 0x80, 0x8b, 0x40, 0x39, 0x88, 0x83, /// 0x710 + 0xc8, 0x83, 0x08, 0x84, 0x48, 0x84, 0x60, 0x87, 0xff, 0xf7, 0x36, 0xff, 0xa1, 0x88, 0x05, 0x46, /// 0x720 + 0xa9, 0x42, 0x25, 0xd9, 0x38, 0x78, 0xc0, 0x07, 0x22, 0xd1, 0x40, 0x2d, 0x01, 0xd2, 0xff, 0xf7, /// 0x730 + 0xd4, 0xfe, 0x22, 0x49, 0x80, 0x2d, 0x02, 0xd2, 0x01, 0x20, 0x88, 0x80, 0x03, 0xe0, 0xff, 0x20, /// 0x740 + 0x41, 0x30, 0x85, 0x42, 0x01, 0xd2, 0x00, 0x20, 0x0c, 0xe0, 0xff, 0x20, 0xe1, 0x30, 0x85, 0x42, /// 0x750 + 0x01, 0xd2, 0x01, 0x20, 0x06, 0xe0, 0x05, 0x20, 0xc0, 0x01, 0x85, 0x42, 0x01, 0xd2, 0x02, 0x20, /// 0x760 + 0x00, 0xe0, 0x03, 0x20, 0x0a, 0x88, 0xf0, 0x23, 0x9a, 0x43, 0x80, 0x01, 0x02, 0x43, 0x0a, 0x80, /// 0x770 + 0x1f, 0x48, 0xa5, 0x80, 0x32, 0x21, 0x41, 0x66, 0x00, 0x20, 0xf8, 0xbd, 0x1d, 0x48, 0x01, 0x78, /// 0x780 + 0x42, 0x22, 0x11, 0x43, 0x01, 0x70, 0x1c, 0x49, 0xc0, 0x14, 0x08, 0x60, 0x1b, 0x49, 0x08, 0x60, /// 0x790 + 0x70, 0x47, 0x0b, 0x49, 0x20, 0x39, 0xca, 0x8e, 0x02, 0x43, 0x08, 0x8f, 0x10, 0x40, 0xc8, 0x86, /// 0x7a0 + 0x04, 0xd0, 0x17, 0x48, 0x01, 0x7f, 0xfb, 0x22, 0x11, 0x40, 0x01, 0x77, 0x70, 0x47, 0x15, 0x48, /// 0x7b0 + 0x81, 0x21, 0x01, 0x80, 0x00, 0x21, 0x01, 0x80, 0x70, 0x47, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, /// 0x7c0 + 0x20, 0x00, 0x00, 0x20, 0xb0, 0x03, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, 0xff, 0xff, 0x00, 0x00, /// 0x7d0 + 0x20, 0x60, 0x00, 0x40, 0x00, 0x44, 0x00, 0x40, 0x20, 0x47, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, /// 0x7e0 + 0x20, 0x38, 0x00, 0x40, 0x00, 0x1a, 0x04, 0x00, 0x80, 0x92, 0x08, 0x00, 0xda, 0x02, 0x00, 0x00, /// 0x7f0 + 0xb0, 0x02, 0x00, 0x20, 0x00, 0x3c, 0x00, 0x40, 0x80, 0xe2, 0x00, 0xe0, 0x00, 0xe1, 0x00, 0xe0, /// 0x800 + 0x20, 0x6c, 0x00, 0x40, 0x00, 0x4c, 0x00, 0x40, 0x10, 0xb5, 0xff, 0x49, 0x08, 0x20, 0x88, 0x83, /// 0x810 + 0xfe, 0x48, 0x00, 0x22, 0x82, 0x80, 0xfe, 0x4b, 0x03, 0x80, 0x39, 0x23, 0x1b, 0x02, 0x03, 0x82, /// 0x820 + 0xfc, 0x48, 0x08, 0x83, 0xfc, 0x49, 0x81, 0x20, 0x08, 0x80, 0xfc, 0x48, 0x0e, 0x21, 0x81, 0x72, /// 0x830 + 0x07, 0x21, 0xc1, 0x73, 0xf8, 0x48, 0xfa, 0x49, 0x20, 0x30, 0x01, 0x80, 0xf9, 0x49, 0x01, 0x23, /// 0x840 + 0x89, 0x78, 0x19, 0x43, 0x01, 0x71, 0xf8, 0x49, 0x09, 0x20, 0x08, 0x70, 0xff, 0xf7, 0xaf, 0xff, /// 0x850 + 0xf7, 0x48, 0xf6, 0x49, 0x41, 0x60, 0xf7, 0x49, 0x0b, 0x78, 0xfb, 0x24, 0x23, 0x40, 0x0b, 0x70, /// 0x860 + 0xf5, 0x49, 0x81, 0x67, 0x01, 0x68, 0x80, 0x30, 0x01, 0x66, 0xec, 0x48, 0x60, 0x38, 0x01, 0x46, /// 0x870 + 0x42, 0x73, 0x40, 0x39, 0x88, 0x8e, 0x40, 0x22, 0x90, 0x43, 0x20, 0x22, 0x10, 0x43, 0x88, 0x86, /// 0x880 + 0x10, 0x46, 0xff, 0xf7, 0x86, 0xff, 0x00, 0x20, 0x10, 0xbd, 0xec, 0x48, 0x00, 0x21, 0x01, 0x72, /// 0x890 + 0x41, 0x72, 0xeb, 0x48, 0x01, 0x21, 0x01, 0x80, 0x01, 0x15, 0x81, 0x80, 0x0f, 0x21, 0x01, 0x80, /// 0x8a0 + 0x02, 0x22, 0x02, 0x81, 0x01, 0x83, 0x04, 0x21, 0x81, 0x82, 0x85, 0xe7, 0xe5, 0x48, 0x01, 0x21, /// 0x8b0 + 0x01, 0x80, 0x02, 0x15, 0x82, 0x80, 0x2b, 0x22, 0x02, 0x80, 0x01, 0x81, 0xe1, 0x49, 0x96, 0x22, /// 0x8c0 + 0x20, 0x31, 0x0a, 0x80, 0x7d, 0x22, 0x8a, 0x80, 0x0f, 0x21, 0x01, 0x83, 0x08, 0x21, 0x81, 0x82, /// 0x8d0 + 0x72, 0xe7, 0x00, 0x28, 0x09, 0xd0, 0x00, 0x29, 0x07, 0xd0, 0x81, 0x42, 0x01, 0xd9, 0x41, 0x1e, /// 0x8e0 + 0x89, 0xb2, 0xd8, 0x4a, 0x20, 0x32, 0x91, 0x80, 0x10, 0x80, 0x65, 0xe7, 0x40, 0x1a, 0x10, 0xb5, /// 0x8f0 + 0x00, 0x23, 0x02, 0xb2, 0x00, 0x2a, 0x02, 0xda, 0x01, 0x23, 0x50, 0x42, 0x02, 0xb2, 0xc7, 0x48, /// 0x900 + 0xa0, 0x38, 0xc4, 0x7c, 0x94, 0x42, 0x1e, 0xda, 0x19, 0x24, 0x64, 0x01, 0xa2, 0x42, 0x0b, 0xdc, /// 0x910 + 0x01, 0x46, 0x09, 0x8a, 0x00, 0x2b, 0x01, 0xd0, 0x49, 0x1e, 0x00, 0xe0, 0x49, 0x1c, 0x01, 0x82, /// 0x920 + 0x09, 0x04, 0x09, 0x0c, 0x08, 0xd0, 0x09, 0xe0, 0xff, 0x22, 0x15, 0x32, 0x51, 0x43, 0xc6, 0x4a, /// 0x930 + 0x51, 0x1a, 0x89, 0x00, 0x09, 0x0c, 0xf2, 0xe7, 0x01, 0x21, 0x01, 0x82, 0x8a, 0xb2, 0xc1, 0x89, /// 0x940 + 0x8a, 0x42, 0x00, 0xd9, 0x01, 0x82, 0x10, 0xbd, 0x00, 0xe0, 0x00, 0xbf, 0x40, 0x1e, 0xfc, 0xd2, /// 0x950 + 0x32, 0xe7, 0x82, 0x18, 0x01, 0xe0, 0x08, 0xc9, 0x08, 0xc0, 0x90, 0x42, 0xfb, 0xd3, 0x2b, 0xe7, /// 0x960 + 0x82, 0x18, 0x03, 0xe0, 0x0b, 0x78, 0x03, 0x70, 0x40, 0x1c, 0x49, 0x1c, 0x90, 0x42, 0xf9, 0xd3, /// 0x970 + 0x22, 0xe7, 0x41, 0x18, 0x00, 0x22, 0x00, 0xe0, 0x04, 0xc0, 0x88, 0x42, 0xfc, 0xd3, 0x1b, 0xe7, /// 0x980 + 0xb2, 0x48, 0x01, 0x21, 0x01, 0x70, 0xb1, 0x4a, 0x05, 0x21, 0x40, 0x32, 0x11, 0x80, 0x00, 0x22, /// 0x990 + 0x02, 0x74, 0xae, 0x49, 0x20, 0x31, 0x0a, 0x74, 0xad, 0x4a, 0x8a, 0x81, 0x13, 0x22, 0x0a, 0x70, /// 0x9a0 + 0x07, 0x21, 0x01, 0x72, 0x08, 0xe7, 0x9d, 0x4a, 0xa0, 0x3a, 0x11, 0x46, 0x40, 0x31, 0xd0, 0x8e, /// 0x9b0 + 0xcb, 0x8a, 0x98, 0x43, 0xd0, 0x86, 0x00, 0x22, 0xca, 0x82, 0x00, 0x28, 0x05, 0xd1, 0x9d, 0x48, /// 0x9c0 + 0x20, 0x38, 0x01, 0x7f, 0x04, 0x22, 0x11, 0x43, 0x01, 0x77, 0xf5, 0xe6, 0x8f, 0x48, 0x00, 0x21, /// 0x9d0 + 0x80, 0x88, 0x00, 0x07, 0x00, 0xd5, 0x02, 0x21, 0x8b, 0x48, 0x80, 0x8b, 0xc0, 0x04, 0x01, 0xd5, /// 0x9e0 + 0x01, 0x20, 0x01, 0x43, 0x9b, 0x48, 0x80, 0x89, 0xc0, 0x06, 0x01, 0xd5, 0x04, 0x20, 0x01, 0x43, /// 0x9f0 + 0x8a, 0x4b, 0xa0, 0x3b, 0x9a, 0x8e, 0x50, 0x07, 0x40, 0x0f, 0x48, 0x40, 0x04, 0xd0, 0xd2, 0x08, /// 0xa00 + 0xd2, 0x00, 0x0a, 0x43, 0x9a, 0x86, 0xc4, 0xe6, 0xd6, 0xe6, 0x02, 0x46, 0x00, 0x20, 0x02, 0xe0, /// 0xa10 + 0x13, 0x78, 0x58, 0x40, 0x52, 0x1c, 0x49, 0x1e, 0xfa, 0xd2, 0xcd, 0xe6, 0x08, 0x22, 0x01, 0x21, /// 0xa20 + 0x01, 0xe0, 0x09, 0x18, 0x40, 0x08, 0x52, 0x1e, 0xfb, 0xd2, 0xc8, 0x07, 0xc0, 0x0f, 0xc3, 0xe6, /// 0xa30 + 0xf8, 0xb5, 0x89, 0x4c, 0x00, 0x26, 0x20, 0x46, 0xff, 0x30, 0xa1, 0x30, 0x84, 0x46, 0x0c, 0x30, /// 0xa40 + 0x01, 0x27, 0xff, 0x34, 0x35, 0x46, 0xc1, 0x34, 0x00, 0x90, 0x60, 0x7a, 0x00, 0x28, 0x0e, 0xd1, /// 0xa50 + 0x60, 0x46, 0xa1, 0x7a, 0x00, 0x7b, 0x81, 0x42, 0x06, 0xd2, 0x01, 0x20, 0xb0, 0x40, 0x49, 0x1c, /// 0xa60 + 0x05, 0x43, 0xa1, 0x72, 0xb6, 0x1c, 0x36, 0xe0, 0x00, 0x20, 0xa0, 0x72, 0x67, 0x72, 0x61, 0x7a, /// 0xa70 + 0x20, 0x7a, 0x81, 0x42, 0x1d, 0xd2, 0xa0, 0x7a, 0x00, 0x28, 0x1d, 0xd0, 0x09, 0x28, 0x06, 0xd2, /// 0xa80 + 0x00, 0x9a, 0x40, 0x1e, 0x89, 0x5c, 0xc1, 0x40, 0xc8, 0x07, 0xc0, 0x0f, 0x14, 0xe0, 0x09, 0x28, /// 0xa90 + 0x05, 0xd0, 0xff, 0x22, 0x01, 0x20, 0xa2, 0x72, 0x49, 0x1c, 0x61, 0x72, 0x0c, 0xe0, 0x00, 0x98, /// 0xaa0 + 0x08, 0x5c, 0xff, 0xf7, 0xbb, 0xff, 0x61, 0x46, 0x09, 0x7b, 0x00, 0x29, 0x04, 0xd1, 0x78, 0x40, /// 0xab0 + 0x02, 0xe0, 0x60, 0x7d, 0xa7, 0x75, 0x78, 0x40, 0x61, 0x7d, 0x79, 0x40, 0x48, 0x40, 0x60, 0x75, /// 0xac0 + 0x40, 0x00, 0x08, 0x43, 0xb0, 0x40, 0x05, 0x43, 0xa0, 0x7a, 0xb6, 0x1c, 0x40, 0x1c, 0xa0, 0x72, /// 0xad0 + 0xa0, 0x7d, 0x01, 0x28, 0x01, 0xd0, 0x10, 0x2e, 0xb7, 0xd3, 0x76, 0x1e, 0x26, 0x75, 0x65, 0x82, /// 0xae0 + 0xf8, 0xbd, 0x70, 0xb5, 0x05, 0x46, 0x41, 0x1c, 0x54, 0x48, 0x53, 0x38, 0xff, 0xf7, 0x8d, 0xff, /// 0xaf0 + 0x59, 0x49, 0x52, 0x4c, 0x49, 0x19, 0xff, 0x31, 0xa1, 0x31, 0x88, 0x73, 0x40, 0x3c, 0xed, 0x1c, /// 0xb00 + 0x25, 0x72, 0x20, 0x7b, 0xe0, 0x72, 0x00, 0x20, 0x60, 0x72, 0xa0, 0x72, 0x60, 0x75, 0x02, 0x26, /// 0xb10 + 0xa6, 0x75, 0xff, 0xf7, 0x8d, 0xff, 0x40, 0x48, 0x20, 0x30, 0x01, 0x88, 0xc9, 0x04, 0x61, 0x7b, /// 0xb20 + 0x03, 0xd5, 0x20, 0x22, 0x11, 0x43, 0x61, 0x73, 0x07, 0xe0, 0xdf, 0x22, 0x11, 0x40, 0x61, 0x73, /// 0xb30 + 0x01, 0x88, 0x01, 0x22, 0x12, 0x03, 0x11, 0x43, 0x01, 0x80, 0x34, 0x49, 0x0a, 0x8a, 0x0c, 0x23, /// 0xb40 + 0x1a, 0x43, 0x0a, 0x82, 0x03, 0x88, 0x03, 0x21, 0x09, 0x02, 0x8b, 0x43, 0x33, 0x49, 0x30, 0x25, /// 0xb50 + 0xca, 0x7a, 0x15, 0x40, 0x2d, 0x01, 0x2b, 0x43, 0x03, 0x80, 0x2f, 0x4d, 0x3f, 0x4b, 0xab, 0x80, /// 0xb60 + 0x2e, 0x81, 0x00, 0x23, 0xdb, 0x43, 0xab, 0x81, 0x48, 0x23, 0x1a, 0x40, 0x25, 0x32, 0x2a, 0x80, /// 0xb70 + 0x62, 0x8a, 0x2a, 0x82, 0x22, 0x7d, 0x2a, 0x75, 0xa2, 0x7b, 0x00, 0x2a, 0x14, 0xd1, 0x0a, 0x46, /// 0xb80 + 0x60, 0x3a, 0x33, 0x4b, 0xd2, 0x8f, 0xb4, 0x3b, 0x9a, 0x42, 0x0d, 0xd9, 0xca, 0x7b, 0x1f, 0x2a, /// 0xb90 + 0x01, 0xd9, 0x1f, 0x22, 0xca, 0x73, 0x02, 0x88, 0xc9, 0x7b, 0x52, 0x09, 0x52, 0x01, 0x0a, 0x43, /// 0xba0 + 0x02, 0x80, 0x01, 0x79, 0x31, 0x43, 0x01, 0x71, 0xff, 0xf7, 0x42, 0xff, 0xff, 0x20, 0x00, 0x02, /// 0xbb0 + 0xa8, 0x81, 0x70, 0xbd, 0x70, 0xb5, 0x00, 0x20, 0xff, 0xf7, 0x8f, 0xfc, 0x1d, 0x49, 0x08, 0x78, /// 0xbc0 + 0xdf, 0x22, 0x10, 0x40, 0x08, 0x70, 0x15, 0x48, 0xef, 0x24, 0xa0, 0x38, 0x82, 0x7c, 0x22, 0x40, /// 0xbd0 + 0x82, 0x74, 0x0d, 0x4a, 0x08, 0x23, 0x93, 0x83, 0x1d, 0x4b, 0xac, 0x3b, 0x13, 0x83, 0x39, 0x22, /// 0xbe0 + 0x0a, 0x4b, 0x12, 0x02, 0x1a, 0x82, 0x00, 0x22, 0x9a, 0x80, 0x1d, 0x88, 0xf0, 0x26, 0xb5, 0x43, /// 0xbf0 + 0x1d, 0x80, 0x12, 0x4b, 0xfb, 0x25, 0x40, 0x3b, 0x5e, 0x7b, 0x2e, 0x40, 0x5e, 0x73, 0x0b, 0x78, /// 0xc00 + 0x2b, 0x40, 0x0b, 0x70, 0x82, 0x87, 0x2b, 0xe0, 0x00, 0x30, 0x00, 0x40, 0x00, 0x34, 0x00, 0x40, /// 0xc10 + 0x01, 0x0a, 0x00, 0x00, 0x3b, 0x3b, 0x00, 0x00, 0x00, 0x38, 0x00, 0x40, 0xa0, 0x00, 0x00, 0x20, /// 0xc20 + 0x0e, 0x30, 0x00, 0x00, 0x60, 0x47, 0x00, 0x00, 0x00, 0x3c, 0x00, 0x40, 0x07, 0x03, 0x00, 0x00, /// 0xc30 + 0x30, 0x02, 0x00, 0x20, 0x40, 0x6c, 0x00, 0x40, 0x3d, 0x15, 0x00, 0x00, 0x30, 0x03, 0x00, 0x20, /// 0xc40 + 0x00, 0x4c, 0x00, 0x40, 0x00, 0x50, 0x00, 0x40, 0x55, 0x32, 0x34, 0x00, 0x00, 0x54, 0x00, 0x40, /// 0xc50 + 0xe7, 0x03, 0x00, 0x00, 0x20, 0x48, 0x00, 0x40, 0x30, 0x01, 0x00, 0x20, 0xdb, 0x05, 0x00, 0x00, /// 0xc60 + 0x01, 0x46, 0x40, 0x31, 0x8a, 0x87, 0x8a, 0x80, 0x40, 0x31, 0x0a, 0x78, 0x22, 0x40, 0x0a, 0x70, /// 0xc70 + 0x81, 0x8e, 0x80, 0x22, 0x11, 0x43, 0x81, 0x86, 0x10, 0x46, 0xff, 0xf7, 0x8a, 0xfd, 0x70, 0xbd, /// 0xc80 + 0x51, 0x4a, 0x10, 0x8b, 0xc0, 0x04, 0xc1, 0x0e, 0x50, 0x48, 0x80, 0x7a, 0x40, 0x00, 0x40, 0x1c, /// 0xc90 + 0x1f, 0x28, 0x00, 0xdd, 0x1f, 0x20, 0x81, 0x42, 0x00, 0xd2, 0x48, 0x1c, 0x11, 0x8b, 0x1f, 0x23, /// 0xca0 + 0x1b, 0x02, 0x99, 0x43, 0x00, 0x02, 0x01, 0x43, 0x11, 0x83, 0x49, 0x49, 0x08, 0x88, 0x07, 0x22, /// 0xcb0 + 0x12, 0x02, 0x90, 0x43, 0x45, 0x4a, 0x20, 0x32, 0x92, 0x78, 0x52, 0x07, 0x52, 0x0d, 0x10, 0x43, /// 0xcc0 + 0x08, 0x80, 0x42, 0x48, 0x60, 0x30, 0x81, 0x7a, 0x1f, 0x29, 0x01, 0xd9, 0x1f, 0x21, 0x81, 0x72, /// 0xcd0 + 0x40, 0x49, 0x0a, 0x88, 0x80, 0x7a, 0x52, 0x09, 0x52, 0x01, 0x02, 0x43, 0x0a, 0x80, 0x6b, 0xe5, /// 0xce0 + 0xf8, 0xb5, 0x41, 0x09, 0x3c, 0x4a, 0x00, 0x29, 0x0a, 0xd0, 0x20, 0x29, 0x01, 0xdb, 0x1f, 0x21, /// 0xcf0 + 0x06, 0xe0, 0x93, 0x7b, 0x8b, 0x42, 0x01, 0xda, 0x49, 0x1e, 0x01, 0xe0, 0x8b, 0x42, 0x00, 0xdd, /// 0xd00 + 0x91, 0x73, 0x47, 0x21, 0x09, 0x02, 0x0e, 0x22, 0x8a, 0x56, 0x30, 0x49, 0x20, 0x39, 0x8e, 0x7f, /// 0xd10 + 0xc9, 0x7f, 0xb3, 0x00, 0x8f, 0x07, 0xbf, 0x0f, 0x39, 0x46, 0xd2, 0x18, 0x1c, 0x31, 0x51, 0x18, /// 0xd20 + 0x29, 0x4a, 0x11, 0x82, 0x23, 0x36, 0x7d, 0x21, 0x70, 0x43, 0xc9, 0x00, 0x00, 0xf0, 0x9e, 0xfb, /// 0xd30 + 0x26, 0x4c, 0x40, 0x34, 0xa1, 0x7c, 0x08, 0x1a, 0x04, 0xd4, 0xe1, 0x7c, 0x40, 0x43, 0x41, 0x43, /// 0xd40 + 0x48, 0x11, 0x00, 0xe0, 0x00, 0x20, 0xe1, 0x8a, 0x0d, 0x18, 0xa0, 0x8a, 0xa8, 0x42, 0x00, 0xd2, /// 0xd50 + 0x05, 0x46, 0x96, 0x2e, 0x00, 0xd1, 0x00, 0x25, 0xb0, 0x00, 0xc0, 0x19, 0x80, 0x02, 0xd2, 0x21, /// 0xd60 + 0x00, 0xf0, 0x84, 0xfb, 0x1e, 0x21, 0x61, 0x56, 0x40, 0x19, 0x08, 0x18, 0x1b, 0x49, 0x88, 0x42, /// 0xd70 + 0x00, 0xd9, 0x08, 0x46, 0x20, 0x82, 0xf8, 0xbd, 0x17, 0x48, 0x17, 0x49, 0x10, 0xb5, 0xc0, 0x38, /// 0xd80 + 0x17, 0x4a, 0x48, 0x31, 0x13, 0x78, 0x5b, 0x06, 0x02, 0xd4, 0x03, 0x68, 0x05, 0x2b, 0x01, 0xd3, /// 0xd90 + 0x00, 0x20, 0x10, 0xbd, 0x0b, 0x78, 0x05, 0x2b, 0xf4, 0xd9, 0x0f, 0x48, 0x81, 0x8d, 0xc2, 0x8d, /// 0xda0 + 0x51, 0x18, 0x02, 0x8e, 0x40, 0x8e, 0x51, 0x18, 0x41, 0x18, 0x0e, 0x48, 0x00, 0xf0, 0x5e, 0xfb, /// 0xdb0 + 0x06, 0x49, 0x08, 0x84, 0x01, 0x20, 0x10, 0xbd, 0x0b, 0x48, 0x0c, 0x4a, 0x01, 0x89, 0x51, 0x1a, /// 0xdc0 + 0x00, 0x22, 0x82, 0x5e, 0x88, 0x18, 0xf7, 0xe4, 0x00, 0x30, 0x00, 0x40, 0x40, 0x00, 0x00, 0x20, /// 0xdd0 + 0x00, 0x34, 0x00, 0x40, 0x20, 0x38, 0x00, 0x40, 0xf0, 0x02, 0x00, 0x20, 0xff, 0x0f, 0x00, 0x00, /// 0xde0 + 0x00, 0x3c, 0x00, 0x40, 0x00, 0x70, 0x17, 0x00, 0x20, 0x47, 0x00, 0x00, 0x31, 0x04, 0x00, 0x00, /// 0xdf0 + 0x1e, 0x49, 0x1f, 0x4b, 0x8a, 0x7d, 0x92, 0x00, 0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0xd0, 0x64, /// 0xe00 + 0x88, 0x7d, 0x40, 0x1c, 0x40, 0x07, 0x40, 0x0f, 0x88, 0x75, 0x70, 0x47, 0x30, 0xb5, 0x19, 0x48, /// 0xe10 + 0x01, 0x79, 0x89, 0x06, 0x28, 0xd4, 0x18, 0x49, 0x40, 0x22, 0x0a, 0x70, 0x80, 0x22, 0x0a, 0x74, /// 0xe20 + 0x12, 0x4a, 0x13, 0x4d, 0xd4, 0x7d, 0xa3, 0x00, 0x5b, 0x19, 0xff, 0x33, 0x4d, 0x33, 0x0b, 0x83, /// 0xe30 + 0x04, 0x23, 0x8b, 0x82, 0x01, 0x23, 0x0b, 0x72, 0x0d, 0x79, 0x72, 0xb6, 0x1d, 0x43, 0x0d, 0x71, /// 0xe40 + 0x64, 0x1c, 0x61, 0x07, 0x49, 0x0f, 0xd1, 0x75, 0x05, 0x21, 0x51, 0x75, 0x62, 0xb6, 0x58, 0x21, /// 0xe50 + 0x01, 0x77, 0xff, 0x21, 0x81, 0x82, 0x09, 0x49, 0x01, 0x82, 0x30, 0x21, 0x01, 0x71, 0x0f, 0x21, /// 0xe60 + 0x01, 0x70, 0x01, 0x79, 0x19, 0x43, 0x01, 0x71, 0x00, 0x20, 0x30, 0xbd, 0x90, 0x02, 0x00, 0x20, /// 0xe70 + 0x30, 0x01, 0x00, 0x20, 0x00, 0x64, 0x00, 0x40, 0x00, 0x60, 0x00, 0x40, 0xc6, 0x03, 0x00, 0x00, /// 0xe80 + 0x95, 0x48, 0x00, 0x68, 0x00, 0x47, 0x94, 0x48, 0x40, 0x68, 0x00, 0x47, 0x92, 0x48, 0x80, 0x68, /// 0xe90 + 0x00, 0x47, 0x91, 0x48, 0xc0, 0x68, 0x00, 0x47, 0x8f, 0x48, 0x00, 0x69, 0x00, 0x47, 0x8e, 0x48, /// 0xea0 + 0x40, 0x69, 0x00, 0x47, 0x8c, 0x48, 0x80, 0x69, 0x00, 0x47, 0x8b, 0x48, 0xc0, 0x69, 0x00, 0x47, /// 0xeb0 + 0x89, 0x48, 0x00, 0x6a, 0x00, 0x47, 0x88, 0x48, 0x40, 0x6a, 0x00, 0x47, 0x86, 0x48, 0x80, 0x6a, /// 0xec0 + 0x00, 0x47, 0x85, 0x48, 0xc0, 0x6a, 0x00, 0x47, 0xf8, 0xb5, 0x84, 0x48, 0x02, 0x7a, 0x01, 0x79, /// 0xed0 + 0x0a, 0x40, 0x02, 0x72, 0xd1, 0x07, 0x19, 0xd0, 0x01, 0x79, 0x49, 0x08, 0x49, 0x00, 0x01, 0x71, /// 0xee0 + 0x00, 0x21, 0x01, 0x74, 0x01, 0x70, 0x7e, 0x4c, 0x65, 0x7d, 0x7e, 0x49, 0x02, 0x23, 0x05, 0x2d, /// 0xef0 + 0x09, 0xd0, 0x0e, 0x79, 0x04, 0x25, 0x2e, 0x43, 0x0e, 0x71, 0x0e, 0x8a, 0xc1, 0x27, 0xbf, 0x00, /// 0xf00 + 0xbe, 0x43, 0x0e, 0x82, 0x65, 0x75, 0x0c, 0x79, 0x1c, 0x43, 0x0c, 0x71, 0x91, 0x07, 0x10, 0xd5, /// 0xf10 + 0x01, 0x79, 0xfd, 0x22, 0x11, 0x40, 0x01, 0x71, 0x70, 0x48, 0x00, 0x24, 0x20, 0x30, 0x04, 0x70, /// 0xf20 + 0x6f, 0x49, 0x10, 0x22, 0x2c, 0x31, 0x88, 0x18, 0xff, 0xf7, 0x13, 0xfd, 0x6c, 0x48, 0xe0, 0x30, /// 0xf30 + 0x44, 0x70, 0xf8, 0xbd, 0xf8, 0xb5, 0x6b, 0x4c, 0xa0, 0x8a, 0x21, 0x8a, 0x08, 0x40, 0xff, 0x21, /// 0xf40 + 0xa1, 0x82, 0xc6, 0x21, 0x06, 0x46, 0xff, 0x22, 0x0e, 0x40, 0x67, 0x4d, 0x6d, 0x32, 0x11, 0x1d, /// 0xf50 + 0x52, 0x59, 0x49, 0x5b, 0xff, 0x35, 0x02, 0x23, 0x61, 0x35, 0x00, 0x2e, 0x25, 0xd0, 0xc4, 0x26, /// 0xf60 + 0x30, 0x40, 0x00, 0x26, 0x00, 0x28, 0x08, 0xd0, 0x20, 0x79, 0x18, 0x43, 0x20, 0x71, 0x20, 0x20, /// 0xf70 + 0xff, 0xf7, 0xea, 0xfc, 0x06, 0x20, 0x68, 0x75, 0x07, 0xe0, 0x68, 0x7d, 0x04, 0x28, 0x03, 0xd1, /// 0xf80 + 0x20, 0x7b, 0x51, 0x18, 0x20, 0x39, 0xc8, 0x77, 0x6e, 0x75, 0x0d, 0x20, 0x20, 0x70, 0x03, 0x20, /// 0xf90 + 0x00, 0x02, 0x20, 0x82, 0xfc, 0x20, 0x20, 0x77, 0x26, 0x71, 0x50, 0x48, 0x06, 0x70, 0x06, 0x74, /// 0xfa0 + 0x01, 0x79, 0x49, 0x08, 0x49, 0x00, 0x01, 0x71, 0xf8, 0xbd, 0x4d, 0x4e, 0xc7, 0x07, 0x20, 0x3e, /// 0xfb0 + 0x76, 0x8e, 0x00, 0x2f, 0x03, 0xd0, 0x30, 0x0a, 0x20, 0x73, 0x6b, 0x75, 0xf8, 0xbd, 0xc0, 0x06, /// 0xfc0 + 0xfc, 0xd5, 0x68, 0x7d, 0x02, 0x28, 0x12, 0xd0, 0x21, 0x20, 0x20, 0x71, 0xff, 0x20, 0xc3, 0x30, /// 0xfd0 + 0x20, 0x82, 0x42, 0x48, 0x40, 0x23, 0x03, 0x70, 0x90, 0x23, 0x03, 0x74, 0x02, 0x83, 0x89, 0x1e, /// 0xfe0 + 0x81, 0x82, 0x01, 0x21, 0x01, 0x72, 0x02, 0x79, 0x0a, 0x43, 0x02, 0x71, 0xf8, 0xbd, 0x26, 0x73, /// 0xff0 + 0x03, 0x20, 0x68, 0x75, 0xf8, 0xbd, 0x3d, 0x49, 0x81, 0x20, 0x08, 0x80, 0x70, 0x47, 0x70, 0xb5, /// 0x1000 + 0x3a, 0x4b, 0x30, 0x20, 0x18, 0x76, 0x36, 0x48, 0x00, 0x24, 0x60, 0x30, 0x81, 0x7d, 0x00, 0x29, /// 0x1010 + 0x0a, 0xd0, 0x42, 0x8a, 0x1a, 0x82, 0x02, 0x7d, 0x1a, 0x75, 0x01, 0x29, 0x02, 0xd0, 0xff, 0xf7, /// 0x1020 + 0x07, 0xfd, 0x70, 0xbd, 0x84, 0x75, 0x70, 0xbd, 0x30, 0x4a, 0x20, 0x32, 0x11, 0x79, 0xfd, 0x25, /// 0x1030 + 0x29, 0x40, 0x11, 0x71, 0x2e, 0x49, 0x8d, 0x7a, 0x1f, 0x2d, 0x01, 0xd9, 0x1f, 0x25, 0x8d, 0x72, /// 0x1040 + 0x15, 0x88, 0x89, 0x7a, 0x6d, 0x09, 0x6d, 0x01, 0x0d, 0x43, 0x15, 0x80, 0x01, 0x21, 0x19, 0x80, /// 0x1050 + 0x04, 0x72, 0x28, 0x48, 0x01, 0x8a, 0x0c, 0x22, 0x91, 0x43, 0x01, 0x82, 0x70, 0xbd, 0x20, 0x48, /// 0x1060 + 0x60, 0x38, 0x01, 0x68, 0x49, 0x1c, 0x01, 0x60, 0x23, 0x49, 0x07, 0x20, 0x08, 0x72, 0x70, 0x47, /// 0x1070 + 0x10, 0xb5, 0x21, 0x4c, 0x20, 0x7a, 0x80, 0x07, 0x02, 0xd5, 0x20, 0x48, 0xff, 0xf7, 0x07, 0xf8, /// 0x1080 + 0x07, 0x20, 0x20, 0x72, 0x10, 0xbd, 0x10, 0xb5, 0x1d, 0x49, 0x8b, 0x89, 0x14, 0x48, 0x16, 0x4c, /// 0x1090 + 0xa0, 0x30, 0x02, 0x7a, 0x52, 0x00, 0x12, 0x19, 0xff, 0x32, 0xc1, 0x32, 0x13, 0x85, 0x02, 0x7a, /// 0x10a0 + 0x52, 0x1c, 0x12, 0x07, 0x12, 0x0f, 0x02, 0x72, 0x0f, 0x20, 0x08, 0x83, 0x10, 0xbd, 0x15, 0x49, /// 0x10b0 + 0x0f, 0x20, 0x08, 0x83, 0x70, 0x47, 0x10, 0xb5, 0x13, 0x48, 0x01, 0x78, 0x49, 0x06, 0x04, 0xd5, /// 0x10c0 + 0x41, 0x21, 0x01, 0x70, 0x11, 0x48, 0xfe, 0xf7, 0xe2, 0xff, 0x11, 0x48, 0x01, 0x79, 0xc9, 0x07, /// 0x10d0 + 0x01, 0xd0, 0x10, 0x21, 0x01, 0x71, 0x10, 0xbd, 0x00, 0x01, 0x00, 0x20, 0x00, 0x60, 0x00, 0x40, /// 0x10e0 + 0x90, 0x02, 0x00, 0x20, 0x00, 0x64, 0x00, 0x40, 0x30, 0x01, 0x00, 0x20, 0x00, 0x38, 0x00, 0x40, /// 0x10f0 + 0xa0, 0x00, 0x00, 0x20, 0x00, 0x34, 0x00, 0x40, 0x00, 0x54, 0x00, 0x40, 0xbd, 0x02, 0x00, 0x00, /// 0x1100 + 0x00, 0x4c, 0x00, 0x40, 0x00, 0x50, 0x00, 0x40, 0x00, 0x3c, 0x00, 0x40, 0x09, 0x08, 0x00, 0x00, /// 0x1110 + 0x40, 0x30, 0x00, 0x40, 0x00, 0x21, 0x41, 0x61, 0x81, 0x61, 0xbb, 0x4a, 0x02, 0x60, 0xc1, 0x61, /// 0x1120 + 0xba, 0x4a, 0x42, 0x60, 0xb8, 0x4a, 0xd2, 0x43, 0x82, 0x60, 0xb8, 0x4a, 0xd2, 0x43, 0xc2, 0x60, /// 0x1130 + 0xb7, 0x4a, 0x01, 0x66, 0x02, 0x61, 0x41, 0x66, 0x70, 0x47, 0xf0, 0xb5, 0xb5, 0x4b, 0x84, 0x46, /// 0x1140 + 0x0f, 0xcb, 0xd9, 0xb0, 0x6c, 0x46, 0x0f, 0xc4, 0x00, 0x23, 0x09, 0xa8, 0x9a, 0x00, 0x61, 0x46, /// 0x1150 + 0x54, 0x18, 0x20, 0x34, 0x21, 0x78, 0x5b, 0x1c, 0x09, 0x06, 0x81, 0x50, 0x65, 0x78, 0x2d, 0x04, /// 0x1160 + 0x29, 0x43, 0x81, 0x50, 0xa5, 0x78, 0x2d, 0x02, 0x29, 0x43, 0x81, 0x50, 0xe4, 0x78, 0x21, 0x43, /// 0x1170 + 0x81, 0x50, 0x10, 0x2b, 0xea, 0xdb, 0x10, 0x21, 0x8c, 0x00, 0x22, 0x18, 0x80, 0x3a, 0x15, 0x6e, /// 0x1180 + 0x53, 0x6f, 0x6b, 0x40, 0x95, 0x6c, 0x12, 0x6c, 0x55, 0x40, 0x6b, 0x40, 0x1f, 0x22, 0xd3, 0x41, /// 0x1190 + 0x49, 0x1c, 0x03, 0x51, 0x50, 0x29, 0xef, 0xdb, 0x61, 0x46, 0x0a, 0x68, 0x08, 0x92, 0x49, 0x68, /// 0x11a0 + 0x63, 0x46, 0x07, 0x91, 0x9b, 0x68, 0x64, 0x46, 0x06, 0x93, 0xe4, 0x68, 0x65, 0x46, 0x05, 0x94, /// 0x11b0 + 0x2d, 0x69, 0x00, 0x26, 0xb6, 0x46, 0x04, 0x95, 0x70, 0x46, 0x86, 0x00, 0x09, 0xa8, 0x87, 0x59, /// 0x11c0 + 0x1b, 0x20, 0x16, 0x46, 0xc6, 0x41, 0xb8, 0x19, 0x0e, 0x46, 0x27, 0x46, 0x1e, 0x40, 0x8f, 0x43, /// 0x11d0 + 0x3e, 0x43, 0x75, 0x19, 0x45, 0x19, 0x00, 0x98, 0x28, 0x18, 0x25, 0x46, 0x1c, 0x46, 0x0b, 0x46, /// 0x11e0 + 0x02, 0x21, 0xcb, 0x41, 0x11, 0x46, 0x02, 0x46, 0x70, 0x46, 0x40, 0x1c, 0x86, 0x46, 0x14, 0x28, /// 0x11f0 + 0xe2, 0xdb, 0x14, 0x20, 0x86, 0x46, 0x86, 0x00, 0x09, 0xa8, 0x87, 0x59, 0x1b, 0x20, 0x16, 0x46, /// 0x1200 + 0xc6, 0x41, 0xb8, 0x19, 0x0e, 0x46, 0x5e, 0x40, 0x66, 0x40, 0x75, 0x19, 0x45, 0x19, 0x01, 0x98, /// 0x1210 + 0x28, 0x18, 0x25, 0x46, 0x1c, 0x46, 0x0b, 0x46, 0x02, 0x21, 0xcb, 0x41, 0x11, 0x46, 0x02, 0x46, /// 0x1220 + 0x70, 0x46, 0x40, 0x1c, 0x86, 0x46, 0x28, 0x28, 0xe5, 0xdb, 0x28, 0x20, 0x86, 0x46, 0x86, 0x00, /// 0x1230 + 0x09, 0xa8, 0x87, 0x59, 0x1b, 0x20, 0x16, 0x46, 0xc6, 0x41, 0xbf, 0x19, 0x1e, 0x46, 0x26, 0x43, /// 0x1240 + 0x18, 0x46, 0x0e, 0x40, 0x20, 0x40, 0x06, 0x43, 0x70, 0x19, 0x3d, 0x18, 0x02, 0x98, 0x28, 0x18, /// 0x1250 + 0x25, 0x46, 0x1c, 0x46, 0x02, 0x23, 0xd9, 0x41, 0x0b, 0x46, 0x11, 0x46, 0x02, 0x46, 0x70, 0x46, /// 0x1260 + 0x40, 0x1c, 0x86, 0x46, 0x3c, 0x28, 0xe2, 0xdb, 0x3c, 0x20, 0x86, 0x46, 0x86, 0x00, 0x09, 0xa8, /// 0x1270 + 0x87, 0x59, 0x1b, 0x20, 0x16, 0x46, 0xc6, 0x41, 0xb8, 0x19, 0x0e, 0x46, 0x5e, 0x40, 0x66, 0x40, /// 0x1280 + 0x75, 0x19, 0x45, 0x19, 0x03, 0x98, 0x28, 0x18, 0x25, 0x46, 0x1c, 0x46, 0x02, 0x23, 0xd9, 0x41, /// 0x1290 + 0x0b, 0x46, 0x11, 0x46, 0x02, 0x46, 0x70, 0x46, 0x40, 0x1c, 0x86, 0x46, 0x50, 0x28, 0xe5, 0xdb, /// 0x12a0 + 0x08, 0x98, 0x82, 0x18, 0x60, 0x46, 0x02, 0x60, 0x07, 0x98, 0x41, 0x18, 0x60, 0x46, 0x41, 0x60, /// 0x12b0 + 0x06, 0x98, 0xc1, 0x18, 0x60, 0x46, 0x81, 0x60, 0x05, 0x98, 0x01, 0x19, 0x60, 0x46, 0xc1, 0x60, /// 0x12c0 + 0x04, 0x98, 0x41, 0x19, 0x60, 0x46, 0x01, 0x61, 0x00, 0x21, 0xc1, 0x61, 0x59, 0xb0, 0xf0, 0xbd, /// 0x12d0 + 0x70, 0xb5, 0x04, 0x46, 0xc0, 0x69, 0x25, 0x46, 0x41, 0x1c, 0x80, 0x22, 0x20, 0x35, 0x00, 0x26, /// 0x12e0 + 0xe1, 0x61, 0x37, 0x28, 0x42, 0x55, 0x03, 0xdc, 0x13, 0xe0, 0x41, 0x1c, 0xe1, 0x61, 0x46, 0x55, /// 0x12f0 + 0xe0, 0x69, 0x40, 0x28, 0xf9, 0xdb, 0x20, 0x46, 0xff, 0xf7, 0x1f, 0xff, 0x02, 0xe0, 0x41, 0x1c, /// 0x1300 + 0xe1, 0x61, 0x46, 0x55, 0xe0, 0x69, 0x38, 0x28, 0xf9, 0xdb, 0x05, 0xe0, 0x41, 0x1c, 0xe1, 0x61, /// 0x1310 + 0x46, 0x55, 0xe0, 0x69, 0x38, 0x28, 0xf9, 0xdb, 0xa1, 0x69, 0x20, 0x46, 0x0a, 0x0e, 0x40, 0x30, /// 0x1320 + 0x02, 0x76, 0x0a, 0x0c, 0x42, 0x76, 0x0a, 0x0a, 0x82, 0x76, 0xc1, 0x76, 0x61, 0x69, 0x0a, 0x0e, /// 0x1330 + 0x02, 0x77, 0x0a, 0x0c, 0x42, 0x77, 0x0a, 0x0a, 0x82, 0x77, 0xc1, 0x77, 0x20, 0x46, 0xff, 0xf7, /// 0x1340 + 0xfc, 0xfe, 0x70, 0xbd, 0x30, 0xb5, 0x0d, 0x46, 0x04, 0x00, 0x08, 0xd0, 0x00, 0x2d, 0x06, 0xd0, /// 0x1350 + 0x60, 0x6e, 0x00, 0x28, 0x04, 0xd1, 0x20, 0x6e, 0x00, 0x28, 0x02, 0xd0, 0x10, 0xe0, 0x01, 0x20, /// 0x1360 + 0x30, 0xbd, 0x20, 0x46, 0xff, 0xf7, 0xb4, 0xff, 0x00, 0x20, 0x01, 0x46, 0x22, 0x18, 0x20, 0x32, /// 0x1370 + 0x40, 0x1c, 0x11, 0x70, 0x40, 0x28, 0xf9, 0xdb, 0x61, 0x61, 0x01, 0x20, 0xa1, 0x61, 0x20, 0x66, /// 0x1380 + 0x00, 0x20, 0x03, 0x22, 0x81, 0x08, 0x83, 0x07, 0x89, 0x00, 0x9b, 0x0f, 0x61, 0x58, 0xd3, 0x1a, /// 0x1390 + 0xdb, 0x00, 0xd9, 0x40, 0x29, 0x54, 0x40, 0x1c, 0x14, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x30, 0xbd, /// 0x13a0 + 0xf0, 0xb5, 0x15, 0x00, 0x0e, 0x46, 0x04, 0x46, 0x15, 0xd0, 0x00, 0x2c, 0x07, 0xd0, 0x00, 0x2e, /// 0x13b0 + 0x05, 0xd0, 0x20, 0x6e, 0x00, 0x28, 0x04, 0xd0, 0x03, 0x20, 0x60, 0x66, 0xf0, 0xbd, 0x01, 0x20, /// 0x13c0 + 0xf0, 0xbd, 0x60, 0x6e, 0x00, 0x28, 0xfb, 0xd1, 0x27, 0x46, 0x20, 0x37, 0x6d, 0x1e, 0x02, 0xd3, /// 0x13d0 + 0x60, 0x6e, 0x00, 0x28, 0x01, 0xd0, 0x00, 0x20, 0xf0, 0xbd, 0xe0, 0x69, 0x31, 0x78, 0x42, 0x1c, /// 0x13e0 + 0xe2, 0x61, 0xc1, 0x55, 0x60, 0x69, 0x08, 0x30, 0x60, 0x61, 0x05, 0xd1, 0xa0, 0x69, 0x40, 0x1c, /// 0x13f0 + 0xa0, 0x61, 0x01, 0xd1, 0x01, 0x20, 0x60, 0x66, 0xe0, 0x69, 0x40, 0x28, 0x02, 0xd1, 0x20, 0x46, /// 0x1400 + 0xff, 0xf7, 0x9b, 0xfe, 0x76, 0x1c, 0xe1, 0xe7, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, /// 0x1410 + 0xf0, 0xe1, 0xd2, 0xc3, 0x14, 0x15, 0x00, 0x00, 0x10, 0xb5, 0x06, 0x49, 0x0c, 0x22, 0x0a, 0x73, /// 0x1420 + 0x19, 0x22, 0x4a, 0x73, 0x88, 0x73, 0x10, 0x20, 0x80, 0x31, 0xc8, 0x77, 0x01, 0x20, 0xff, 0xf7, /// 0x1430 + 0x58, 0xfb, 0x10, 0xbd, 0xd0, 0x02, 0x00, 0x20, 0x10, 0xb5, 0x09, 0x48, 0x07, 0x49, 0x41, 0x60, /// 0x1440 + 0x08, 0x49, 0x81, 0x67, 0x08, 0x22, 0x08, 0x49, 0x7c, 0x30, 0xff, 0xf7, 0x82, 0xfa, 0x04, 0x48, /// 0x1450 + 0x08, 0x22, 0x05, 0x49, 0x84, 0x30, 0xff, 0xf7, 0x7c, 0xfa, 0x10, 0xbd, 0xa5, 0x18, 0x00, 0x00, /// 0x1460 + 0x30, 0x02, 0x00, 0x20, 0x3d, 0x15, 0x00, 0x00, 0x64, 0x1b, 0x00, 0x00, 0x30, 0xb5, 0x0b, 0x46, /// 0x1470 + 0x01, 0x46, 0x00, 0x20, 0x20, 0x22, 0x01, 0x24, 0x09, 0xe0, 0x0d, 0x46, 0xd5, 0x40, 0x9d, 0x42, /// 0x1480 + 0x05, 0xd3, 0x1d, 0x46, 0x95, 0x40, 0x49, 0x1b, 0x25, 0x46, 0x95, 0x40, 0x40, 0x19, 0x15, 0x46, /// 0x1490 + 0x52, 0x1e, 0x00, 0x2d, 0xf1, 0xdc, 0x30, 0xbd, 0x70, 0xb5, 0x00, 0x24, 0x25, 0x46, 0x00, 0x28, /// 0x14a0 + 0x01, 0xda, 0x01, 0x24, 0x40, 0x42, 0x00, 0x29, 0x01, 0xda, 0x01, 0x25, 0x49, 0x42, 0xff, 0xf7, /// 0x14b0 + 0xdd, 0xff, 0xac, 0x42, 0x00, 0xd0, 0x40, 0x42, 0x00, 0x2c, 0x00, 0xd0, 0x49, 0x42, 0x70, 0xbd, /// 0x14c0 + 0x30, 0xb4, 0x74, 0x46, 0x64, 0x1e, 0x25, 0x78, 0x64, 0x1c, 0xab, 0x42, 0x00, 0xd2, 0x1d, 0x46, /// 0x14d0 + 0x63, 0x5d, 0x5b, 0x00, 0xe3, 0x18, 0x30, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, /// 0x14e0 + 0x07, 0x07, 0x07, 0x07, 0xc9, 0x0e, 0x00, 0x00, 0x5f, 0x10, 0x00, 0x00, 0x87, 0x10, 0x00, 0x00, /// 0x14f0 + 0xaf, 0x10, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x35, 0x0f, 0x00, 0x00, 0xf7, 0x0f, 0x00, 0x00, /// 0x1500 + 0x79, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, 0x79, 0x00, 0x00, 0x00, /// 0x1510 + 0xb7, 0x10, 0x00, 0x00, 0x99, 0x79, 0x82, 0x5a, 0xa1, 0xeb, 0xd9, 0x6e, 0xdc, 0xbc, 0x1b, 0x8f, /// 0x1520 + 0xd6, 0xc1, 0x62, 0xca, 0xfe, 0x48, 0x32, 0x21, 0x41, 0x66, 0x01, 0x46, 0x08, 0x22, 0x40, 0x39, /// 0x1530 + 0x8a, 0x72, 0x40, 0x39, 0x09, 0x68, 0x32, 0x39, 0x81, 0x65, 0x70, 0x47, 0xf8, 0xb5, 0xff, 0xf7, /// 0x1540 + 0x45, 0xfa, 0xf8, 0x4e, 0xf4, 0x89, 0x00, 0x2c, 0x6b, 0xd0, 0x00, 0x27, 0x35, 0x46, 0xe0, 0x05, /// 0x1550 + 0x40, 0x35, 0xf7, 0x81, 0x00, 0x28, 0x0f, 0xda, 0xff, 0xf7, 0x2c, 0xfb, 0x02, 0x20, 0xf2, 0x4a, /// 0x1560 + 0x28, 0x70, 0x5a, 0x21, 0x11, 0x70, 0xf0, 0x48, 0x10, 0x23, 0x40, 0x30, 0x03, 0x70, 0x11, 0x70, /// 0x1570 + 0x07, 0x72, 0x80, 0x21, 0x01, 0x70, 0x54, 0xe0, 0xec, 0x48, 0x21, 0x04, 0x04, 0xd5, 0x01, 0x8d, /// 0x1580 + 0x01, 0x22, 0x52, 0x02, 0x11, 0x43, 0x01, 0x85, 0xe1, 0x06, 0x04, 0xd5, 0x01, 0x8d, 0xff, 0x22, /// 0x1590 + 0x01, 0x32, 0x11, 0x43, 0x01, 0x85, 0xe1, 0x07, 0x08, 0x22, 0x00, 0x29, 0x02, 0xd0, 0x69, 0x78, /// 0x15a0 + 0x11, 0x43, 0x69, 0x70, 0xa1, 0x05, 0x15, 0xd5, 0xde, 0x49, 0x20, 0x39, 0x8b, 0x79, 0x1b, 0x06, /// 0x15b0 + 0x06, 0xd5, 0x8f, 0x71, 0xcf, 0x71, 0x01, 0x8d, 0x01, 0x22, 0x11, 0x43, 0x01, 0x85, 0x09, 0xe0, /// 0x15c0 + 0xda, 0x48, 0x0b, 0x7b, 0x00, 0x8d, 0x00, 0x2b, 0x0e, 0xd0, 0x20, 0x23, 0x18, 0x43, 0xd7, 0x4b, /// 0x15d0 + 0x18, 0x85, 0xca, 0x71, 0xa0, 0x06, 0x01, 0xd5, 0xff, 0xf7, 0xe5, 0xf9, 0x60, 0x06, 0x0b, 0xd5, /// 0x15e0 + 0x30, 0x7b, 0x5a, 0x28, 0x02, 0xd0, 0x07, 0xe0, 0x10, 0x23, 0xef, 0xe7, 0x70, 0x7b, 0x40, 0x21, /// 0x15f0 + 0x08, 0x43, 0x70, 0x73, 0xce, 0x48, 0x80, 0x47, 0x20, 0x07, 0x01, 0xd5, 0xff, 0xf7, 0x92, 0xff, /// 0x1600 + 0xa0, 0x07, 0x01, 0xd5, 0x00, 0xf0, 0xb0, 0xfd, 0x20, 0x06, 0x03, 0xd5, 0xa8, 0x78, 0x01, 0x21, /// 0x1610 + 0x08, 0x43, 0xa8, 0x70, 0x60, 0x07, 0x03, 0xd5, 0xa8, 0x78, 0x20, 0x21, 0x08, 0x43, 0xa8, 0x70, /// 0x1620 + 0x37, 0x73, 0x00, 0x20, 0xf8, 0xbd, 0xbe, 0x48, 0x10, 0xb5, 0x80, 0x38, 0x01, 0x68, 0x80, 0x30, /// 0x1630 + 0x82, 0x6d, 0x43, 0x6e, 0x8a, 0x1a, 0x9a, 0x42, 0x0c, 0xdb, 0x81, 0x65, 0x83, 0x21, 0x89, 0x00, /// 0x1640 + 0x81, 0x85, 0xb8, 0x48, 0x20, 0x38, 0xc1, 0x7e, 0xb5, 0x48, 0x20, 0x30, 0x81, 0x73, 0x01, 0x20, /// 0x1650 + 0xff, 0xf7, 0x47, 0xfa, 0x10, 0xbd, 0xb3, 0x48, 0x10, 0xb5, 0x10, 0x22, 0xb5, 0x49, 0x50, 0x30, /// 0x1660 + 0xff, 0xf7, 0x77, 0xf9, 0xaf, 0x48, 0x10, 0x22, 0xb3, 0x49, 0x28, 0x30, 0xff, 0xf7, 0x71, 0xf9, /// 0x1670 + 0xac, 0x48, 0x19, 0x21, 0x20, 0x38, 0x02, 0x46, 0x81, 0x77, 0x40, 0x32, 0xd1, 0x70, 0x00, 0x21, /// 0x1680 + 0xc1, 0x77, 0xa9, 0x49, 0x80, 0x20, 0x08, 0x82, 0x10, 0xbd, 0x10, 0xb5, 0xff, 0xf7, 0xe3, 0xff, /// 0x1690 + 0xa4, 0x49, 0xf7, 0x22, 0x48, 0x7b, 0x10, 0x40, 0x48, 0x73, 0x08, 0x46, 0xa7, 0x4a, 0x40, 0x30, /// 0x16a0 + 0xc2, 0x60, 0x82, 0x60, 0x9e, 0x48, 0xa6, 0x4a, 0x80, 0x30, 0x42, 0x81, 0xff, 0x38, 0x01, 0x38, /// 0x16b0 + 0x02, 0x68, 0x80, 0x30, 0x02, 0x66, 0xc2, 0x65, 0x43, 0x6e, 0xd2, 0x1a, 0x82, 0x65, 0x0f, 0x20, /// 0x16c0 + 0x88, 0x72, 0x98, 0x48, 0x03, 0x21, 0x20, 0x30, 0x81, 0x70, 0x95, 0x48, 0x05, 0x21, 0x40, 0x38, /// 0x16d0 + 0x81, 0x72, 0x10, 0xbd, 0x70, 0xb5, 0x9b, 0x48, 0x01, 0x88, 0x07, 0x22, 0x12, 0x02, 0x91, 0x43, /// 0x16e0 + 0x01, 0x80, 0x90, 0x48, 0x08, 0x22, 0x41, 0x7b, 0x04, 0x46, 0x11, 0x43, 0x41, 0x73, 0x0f, 0x21, /// 0x16f0 + 0x81, 0x72, 0x90, 0x49, 0x00, 0x25, 0x20, 0x34, 0xa5, 0x70, 0x10, 0x22, 0x10, 0x31, 0x50, 0x30, /// 0x1700 + 0xff, 0xf7, 0x27, 0xf9, 0x8c, 0x49, 0x20, 0x46, 0x10, 0x22, 0x10, 0x31, 0x08, 0x30, 0xff, 0xf7, /// 0x1710 + 0x20, 0xf9, 0x20, 0x46, 0x8c, 0x49, 0x20, 0x30, 0x01, 0x82, 0xff, 0x21, 0x82, 0x4a, 0x71, 0x31, /// 0x1720 + 0x11, 0x82, 0x01, 0x46, 0x55, 0x22, 0x60, 0x39, 0x8a, 0x77, 0xe2, 0x70, 0xcd, 0x77, 0x87, 0x49, /// 0x1730 + 0xc1, 0x60, 0x82, 0x49, 0x81, 0x60, 0x7a, 0x48, 0x80, 0x30, 0x81, 0x66, 0x04, 0x21, 0xc0, 0x38, /// 0x1740 + 0x81, 0x72, 0x70, 0xbd, 0x10, 0xb5, 0x76, 0x48, 0x81, 0x49, 0xc1, 0x62, 0x41, 0x21, 0x49, 0x02, /// 0x1750 + 0x01, 0x86, 0x80, 0x21, 0x20, 0x30, 0x81, 0x74, 0x05, 0x20, 0xff, 0xf7, 0xc2, 0xf9, 0x10, 0xbd, /// 0x1760 + 0x10, 0xb5, 0x6f, 0x48, 0x7b, 0x49, 0xc1, 0x62, 0x6e, 0x21, 0x01, 0x86, 0x7a, 0x49, 0x20, 0x30, /// 0x1770 + 0xca, 0x7b, 0x82, 0x74, 0x0a, 0x7c, 0xc2, 0x74, 0x49, 0x7c, 0x01, 0x75, 0x07, 0x20, 0xff, 0xf7, /// 0x1780 + 0xb0, 0xf9, 0x10, 0xbd, 0x10, 0xb5, 0x67, 0x49, 0x08, 0x88, 0xc0, 0x08, 0xff, 0x28, 0x00, 0xd9, /// 0x1790 + 0xff, 0x20, 0xc8, 0x72, 0xff, 0x22, 0x62, 0x49, 0x0d, 0x32, 0x8a, 0x85, 0x20, 0x31, 0x88, 0x73, /// 0x17a0 + 0x01, 0x20, 0xff, 0xf7, 0x9e, 0xf9, 0x10, 0xbd, 0xf8, 0xb5, 0x5e, 0x4d, 0x5f, 0x4c, 0x40, 0x35, /// 0x17b0 + 0x68, 0x78, 0x26, 0x46, 0x27, 0x46, 0xc1, 0x06, 0x40, 0x36, 0xc0, 0x37, 0x00, 0x29, 0x0a, 0xda, /// 0x17c0 + 0xef, 0x21, 0x08, 0x40, 0x68, 0x70, 0xa1, 0x8e, 0x01, 0x20, 0xc0, 0x02, 0x01, 0x43, 0xa1, 0x86, /// 0x17d0 + 0xfe, 0xf7, 0xdf, 0xff, 0x10, 0xe0, 0x39, 0x79, 0x0a, 0x07, 0x06, 0xd5, 0x32, 0x7e, 0x1e, 0x2a, /// 0x17e0 + 0x03, 0xd0, 0x20, 0x21, 0x08, 0x43, 0x68, 0x70, 0x06, 0xe0, 0x48, 0x06, 0x04, 0xd5, 0xbf, 0x20, /// 0x17f0 + 0x01, 0x40, 0x80, 0x20, 0x01, 0x43, 0x39, 0x71, 0x38, 0x79, 0x81, 0x07, 0x02, 0xd5, 0x31, 0x7e, /// 0x1800 + 0x3f, 0x29, 0x16, 0xd0, 0x69, 0x78, 0x49, 0x06, 0x02, 0xd5, 0x31, 0x7e, 0x4f, 0x29, 0x13, 0xd0, /// 0x1810 + 0x00, 0x07, 0x09, 0xd5, 0x30, 0x7e, 0x1e, 0x28, 0x06, 0xd0, 0xa0, 0x8e, 0x10, 0x21, 0x08, 0x43, /// 0x1820 + 0xa0, 0x86, 0x08, 0x46, 0xfe, 0xf7, 0xb5, 0xff, 0xa8, 0x78, 0xbf, 0x21, 0x08, 0x40, 0xa8, 0x70, /// 0x1830 + 0xf8, 0xbd, 0x01, 0xf0, 0x52, 0xfc, 0xf7, 0xe7, 0x3a, 0x48, 0x19, 0x30, 0x01, 0xf0, 0x28, 0xfc, /// 0x1840 + 0xf2, 0xe7, 0x10, 0xb5, 0x45, 0x49, 0x0d, 0x20, 0x08, 0x72, 0xff, 0xf7, 0x2f, 0xf8, 0x37, 0x48, /// 0x1850 + 0x00, 0x21, 0x01, 0x81, 0x33, 0x49, 0x42, 0x4a, 0x49, 0x7b, 0x82, 0x81, 0x0b, 0x07, 0x7d, 0x21, /// 0x1860 + 0x01, 0x82, 0x96, 0x21, 0xc1, 0x81, 0x2a, 0x21, 0xc1, 0x74, 0x81, 0x7c, 0x20, 0x22, 0x11, 0x43, /// 0x1870 + 0x81, 0x74, 0x10, 0xbd, 0x10, 0xb5, 0x39, 0x48, 0x00, 0x7e, 0x80, 0x07, 0x11, 0xd5, 0x01, 0x20, /// 0x1880 + 0x80, 0x03, 0xfe, 0xf7, 0x86, 0xff, 0xff, 0xf7, 0x95, 0xf9, 0x26, 0x48, 0x02, 0x21, 0x40, 0x30, /// 0x1890 + 0x01, 0x70, 0x25, 0x49, 0x5a, 0x20, 0x08, 0x70, 0x23, 0x49, 0x80, 0x20, 0x40, 0x31, 0x08, 0x70, /// 0x18a0 + 0xfe, 0xe7, 0x10, 0xbd, 0xfe, 0xb5, 0xff, 0xf7, 0xe5, 0xff, 0x2e, 0x48, 0x01, 0x90, 0x00, 0x7d, /// 0x18b0 + 0x00, 0x28, 0x12, 0xd0, 0x40, 0x1e, 0x00, 0x06, 0x01, 0x99, 0x00, 0x0e, 0x08, 0x75, 0x0c, 0xd1, /// 0x18c0 + 0x26, 0x48, 0x20, 0x30, 0x01, 0x78, 0x20, 0x22, 0x11, 0x43, 0x01, 0x70, 0x17, 0x48, 0x10, 0x22, /// 0x18d0 + 0x81, 0x7c, 0x11, 0x43, 0x81, 0x74, 0xff, 0xf7, 0xb4, 0xff, 0x12, 0x4e, 0x40, 0x36, 0xb0, 0x78, /// 0x18e0 + 0x40, 0x06, 0x01, 0xd5, 0xff, 0xf7, 0x60, 0xff, 0x0e, 0x48, 0x20, 0x38, 0x81, 0x7f, 0x40, 0x30, /// 0x18f0 + 0x4b, 0x29, 0x01, 0xd9, 0x01, 0x21, 0x04, 0xe0, 0x23, 0x29, 0x01, 0xd9, 0x00, 0x21, 0x00, 0xe0, /// 0x1900 + 0x03, 0x21, 0x81, 0x70, 0x17, 0x48, 0x06, 0x4d, 0x40, 0x38, 0x00, 0x90, 0x40, 0x78, 0x40, 0x35, /// 0x1910 + 0x00, 0x28, 0x2d, 0xd1, 0x28, 0x7a, 0x00, 0x28, 0x2a, 0xd1, 0x28, 0x46, 0x3c, 0x38, 0x23, 0xe0, /// 0x1920 + 0xb0, 0x02, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, 0x00, 0x30, 0x00, 0x40, 0x00, 0x00, 0x00, 0x20, /// 0x1930 + 0x11, 0x06, 0x00, 0x20, 0x6c, 0x1b, 0x00, 0x00, 0x44, 0x31, 0x00, 0x00, 0x04, 0x0a, 0x0a, 0x00, /// 0x1940 + 0xdc, 0x05, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, 0x85, 0x09, 0x00, 0x00, 0x31, 0x14, 0x14, 0x00, /// 0x1950 + 0x0c, 0x51, 0x0a, 0x00, 0x0c, 0x71, 0x12, 0x00, 0x20, 0x47, 0x00, 0x00, 0x20, 0x6c, 0x00, 0x40, /// 0x1960 + 0x88, 0x13, 0x00, 0x00, 0xb0, 0x03, 0x00, 0x20, 0xfe, 0xf7, 0x84, 0xfd, 0xfe, 0xf7, 0x47, 0xfe, /// 0x1970 + 0x72, 0x78, 0x73, 0x4f, 0xd0, 0x06, 0x00, 0x28, 0x11, 0xda, 0xbb, 0x89, 0x39, 0x46, 0x58, 0x1c, /// 0x1980 + 0xb8, 0x81, 0xc0, 0x39, 0x48, 0x8c, 0x83, 0x42, 0x09, 0xd9, 0xef, 0x20, 0x02, 0x40, 0x72, 0x70, /// 0x1990 + 0x8a, 0x8e, 0x01, 0x20, 0x80, 0x02, 0x02, 0x43, 0x8a, 0x86, 0xfe, 0xf7, 0xfa, 0xfe, 0x30, 0x78, /// 0x19a0 + 0xc0, 0x06, 0x23, 0xd5, 0x66, 0x48, 0xc0, 0x38, 0x81, 0x7c, 0x02, 0x91, 0x89, 0x06, 0x1b, 0xd5, /// 0x19b0 + 0x40, 0x89, 0x64, 0x49, 0x48, 0x43, 0x64, 0x49, 0xff, 0xf7, 0x58, 0xfd, 0x60, 0x4c, 0x12, 0x30, /// 0x19c0 + 0x80, 0x3c, 0xe1, 0x78, 0x06, 0x29, 0x15, 0xd0, 0x22, 0x46, 0x40, 0x3a, 0x13, 0x6b, 0x18, 0x18, /// 0x19d0 + 0x49, 0x1c, 0x10, 0x63, 0xe1, 0x70, 0x5a, 0x48, 0xc0, 0x38, 0x01, 0x8a, 0xc0, 0x89, 0xfe, 0xf7, /// 0x19e0 + 0x78, 0xff, 0x30, 0x78, 0xc0, 0x06, 0x01, 0xd5, 0x01, 0xf0, 0xe9, 0xfa, 0x28, 0x7a, 0x00, 0x28, /// 0x19f0 + 0x42, 0xd1, 0x1c, 0xe0, 0x52, 0x49, 0xc0, 0x39, 0x09, 0x6b, 0x08, 0x18, 0x07, 0x21, 0xff, 0xf7, /// 0x1a00 + 0x35, 0xfd, 0x4f, 0x49, 0x80, 0xb2, 0xc0, 0x39, 0x08, 0x81, 0x4d, 0x4a, 0x00, 0x21, 0xe1, 0x70, /// 0x1a10 + 0xc0, 0x3a, 0x11, 0x63, 0x02, 0x99, 0xc9, 0x07, 0xdd, 0xd1, 0x91, 0x89, 0x43, 0x1a, 0x00, 0xd5, /// 0x1a20 + 0x5b, 0x42, 0xd2, 0x7c, 0x93, 0x42, 0xd6, 0xdd, 0xfe, 0xf7, 0x60, 0xff, 0xd3, 0xe7, 0x47, 0x48, /// 0x1a30 + 0xe9, 0x7a, 0x04, 0x46, 0xff, 0x34, 0x41, 0x34, 0x20, 0x46, 0xc0, 0x30, 0x02, 0x90, 0x00, 0x29, /// 0x1a40 + 0x1b, 0xd0, 0x49, 0x1e, 0xe9, 0x72, 0xa0, 0x7a, 0x03, 0x28, 0x76, 0xd3, 0x72, 0xb6, 0x40, 0x48, /// 0x1a50 + 0xfe, 0xf7, 0x1d, 0xfb, 0x62, 0xb6, 0x28, 0x7b, 0xe9, 0x7a, 0x40, 0x1e, 0x81, 0x42, 0x6c, 0xd1, /// 0x1a60 + 0x02, 0x99, 0x00, 0x20, 0x08, 0x82, 0x88, 0x81, 0x68, 0x7b, 0x80, 0x06, 0x65, 0xd4, 0x39, 0x48, /// 0x1a70 + 0x01, 0x88, 0x82, 0x14, 0x91, 0x43, 0x01, 0x80, 0x5f, 0xe0, 0x00, 0x20, 0x68, 0x74, 0xa0, 0x7a, /// 0x1a80 + 0x03, 0x00, 0xff, 0xf7, 0x1d, 0xfd, 0x09, 0x06, 0x15, 0x1a, 0x26, 0x3f, 0x42, 0x45, 0x55, 0x58, /// 0x1a90 + 0x5a, 0x00, 0x31, 0x48, 0x00, 0x68, 0x1d, 0x28, 0x4f, 0xd9, 0x08, 0x20, 0x28, 0x73, 0x2e, 0x48, /// 0x1aa0 + 0x32, 0x21, 0x80, 0x30, 0x41, 0x66, 0x01, 0x20, 0xa0, 0x72, 0xff, 0xf7, 0x6b, 0xfe, 0x44, 0xe0, /// 0x1ab0 + 0xff, 0xf7, 0x56, 0xfe, 0x02, 0x20, 0xa0, 0x72, 0x3f, 0xe0, 0x34, 0x20, 0xf0, 0x70, 0x1e, 0x20, /// 0x1ac0 + 0x28, 0x73, 0xff, 0xf7, 0x3f, 0xfe, 0x03, 0x20, 0xa0, 0x72, 0x24, 0x49, 0x01, 0x20, 0xc8, 0x77, /// 0x1ad0 + 0x33, 0xe0, 0x00, 0x98, 0x00, 0x78, 0xc0, 0x07, 0x02, 0xd0, 0xff, 0xf7, 0xfb, 0xfd, 0x01, 0xe0, /// 0x1ae0 + 0xff, 0xf7, 0xd3, 0xfd, 0x16, 0x49, 0xff, 0x20, 0xf5, 0x30, 0xc0, 0x39, 0x48, 0x84, 0x00, 0x20, /// 0x1af0 + 0xb0, 0x64, 0xff, 0x22, 0x78, 0x71, 0x60, 0x32, 0xfa, 0x81, 0x01, 0x9a, 0x10, 0x75, 0x18, 0x48, /// 0x1b00 + 0x08, 0x87, 0x1a, 0xe0, 0x01, 0xf0, 0x62, 0xf9, 0x17, 0xe0, 0x00, 0xf0, 0xcb, 0xff, 0x14, 0xe0, /// 0x1b10 + 0x00, 0x98, 0x00, 0x78, 0xc0, 0x07, 0x01, 0xd0, 0x07, 0x20, 0x00, 0xe0, 0x05, 0x20, 0xa0, 0x72, /// 0x1b20 + 0x0e, 0x49, 0x00, 0x20, 0x40, 0x31, 0xc8, 0x71, 0x02, 0x98, 0xb1, 0x68, 0x81, 0x66, 0x04, 0xe0, /// 0x1b30 + 0x00, 0xf0, 0x59, 0xfb, 0x01, 0xe0, 0xff, 0xf7, 0x76, 0xfd, 0x00, 0x20, 0xfe, 0xbd, 0x00, 0x00, /// 0x1b40 + 0xc0, 0x00, 0x00, 0x20, 0x34, 0x08, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x30, 0x01, 0x00, 0x20, /// 0x1b50 + 0x5f, 0x1f, 0x00, 0x00, 0x20, 0x38, 0x00, 0x40, 0x30, 0x02, 0x00, 0x20, 0x50, 0x03, 0x00, 0x20, /// 0x1b60 + 0xd8, 0xbf, 0x00, 0x00, 0x32, 0x31, 0x3f, 0x03, 0x32, 0x31, 0x3f, 0x14, 0xf3, 0x04, 0x19, 0x0c, /// 0x1b70 + 0xea, 0x00, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x08, 0x32, 0x04, /// 0x1b80 + 0x75, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x01, 0xd2, /// 0x1b90 + 0x01, 0x20, 0x70, 0x47, 0x80, 0x28, 0x03, 0xd2, 0x20, 0x38, 0x00, 0x11, 0x80, 0x1c, 0x70, 0x47, /// 0x1ba0 + 0xe0, 0x28, 0x03, 0xd2, 0x80, 0x38, 0xc0, 0x10, 0x08, 0x30, 0x70, 0x47, 0xe0, 0x38, 0x80, 0x10, /// 0x1bb0 + 0x14, 0x30, 0x70, 0x47, 0x41, 0x07, 0x89, 0x0f, 0x03, 0x29, 0x0b, 0xd1, 0x01, 0x07, 0x03, 0xd5, /// 0x1bc0 + 0x80, 0x09, 0x02, 0x28, 0x04, 0xd0, 0x05, 0xe0, 0x00, 0x09, 0x03, 0xd0, 0x0c, 0x28, 0x01, 0xd8, /// 0x1bd0 + 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x1e, 0x28, 0x08, 0xd0, 0xc1, 0x43, 0x09, 0x07, /// 0x1be0 + 0x07, 0xd1, 0x01, 0x09, 0x06, 0x29, 0x04, 0xd2, 0x00, 0x06, 0x00, 0x0f, 0x01, 0xd0, 0x01, 0x20, /// 0x1bf0 + 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x10, 0xb5, 0xf9, 0x48, 0xf7, 0x22, 0xc1, 0x79, 0x11, 0x40, /// 0x1c00 + 0xc1, 0x71, 0xf7, 0x49, 0x00, 0x20, 0x20, 0x39, 0x08, 0x85, 0x80, 0x20, 0xfe, 0xf7, 0xc1, 0xfd, /// 0x1c10 + 0x10, 0xbd, 0xf8, 0xb5, 0xf3, 0x4a, 0x10, 0x7d, 0xff, 0xf7, 0xde, 0xff, 0xf2, 0x49, 0x11, 0x24, /// 0x1c20 + 0x64, 0x01, 0x0f, 0x19, 0x85, 0x23, 0x09, 0x24, 0x9b, 0x00, 0xa4, 0x01, 0xcb, 0x18, 0x0e, 0x19, /// 0x1c30 + 0x00, 0x28, 0x18, 0xd0, 0xf0, 0x79, 0x40, 0x1c, 0xc0, 0xb2, 0xf0, 0x71, 0x06, 0x28, 0x01, 0xd9, /// 0x1c40 + 0x06, 0x20, 0xf0, 0x71, 0xc2, 0xb2, 0xe6, 0x48, 0x19, 0x46, 0x38, 0x30, 0xfe, 0xf7, 0x88, 0xfe, /// 0x1c50 + 0xe3, 0x48, 0x40, 0x22, 0x60, 0x30, 0x81, 0x78, 0x11, 0x43, 0x81, 0x70, 0xf8, 0x7f, 0xef, 0x21, /// 0x1c60 + 0x08, 0x40, 0xf8, 0x77, 0xf8, 0xbd, 0xde, 0x4c, 0x10, 0x7d, 0x20, 0x3c, 0x25, 0x46, 0x20, 0x35, /// 0x1c70 + 0x15, 0x28, 0x17, 0xd0, 0xff, 0xf7, 0x9e, 0xff, 0x01, 0x1e, 0xdc, 0x48, 0x57, 0xd0, 0x11, 0x7d, /// 0x1c80 + 0xea, 0x79, 0xc9, 0x07, 0xd2, 0x07, 0xc9, 0x0f, 0xd2, 0x0f, 0x91, 0x42, 0x4a, 0xd1, 0xf1, 0x79, /// 0x1c90 + 0xeb, 0x7b, 0x8c, 0x46, 0xaa, 0x7b, 0x59, 0x18, 0x91, 0x42, 0x22, 0xd9, 0xe9, 0x73, 0x20, 0x8d, /// 0x1ca0 + 0x02, 0x21, 0x41, 0xe0, 0x50, 0x7d, 0x01, 0x06, 0x14, 0xd5, 0xe9, 0x79, 0x8a, 0x06, 0x92, 0x0f, /// 0x1cb0 + 0x02, 0xd0, 0x20, 0x8d, 0x04, 0x21, 0x37, 0xe0, 0x22, 0x8d, 0x08, 0x23, 0x40, 0x06, 0x1a, 0x43, /// 0x1cc0 + 0x40, 0x0e, 0x22, 0x85, 0x40, 0x1c, 0xa8, 0x73, 0x00, 0x20, 0xe8, 0x73, 0x48, 0x08, 0x40, 0x00, /// 0x1cd0 + 0xe8, 0x71, 0xf8, 0xbd, 0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8d, 0xff, 0x20, 0x8d, 0x08, 0x21, /// 0x1ce0 + 0x22, 0xe0, 0xc0, 0x49, 0x18, 0x18, 0x62, 0x46, 0x15, 0x31, 0xfe, 0xf7, 0x39, 0xfe, 0xe8, 0x7b, /// 0x1cf0 + 0xf1, 0x79, 0x01, 0x22, 0x40, 0x18, 0xc1, 0xb2, 0xe9, 0x73, 0xe8, 0x79, 0x40, 0x23, 0x50, 0x40, /// 0x1d00 + 0xe8, 0x71, 0x22, 0x8d, 0x1a, 0x43, 0x22, 0x85, 0xb6, 0x4a, 0x32, 0x23, 0x80, 0x3a, 0x53, 0x66, /// 0x1d10 + 0x05, 0x22, 0x3a, 0x77, 0xaa, 0x7b, 0x91, 0x42, 0xdb, 0xd1, 0x10, 0x21, 0x08, 0x43, 0xe8, 0x71, /// 0x1d20 + 0x08, 0x46, 0x18, 0xe0, 0x20, 0x8d, 0x40, 0x21, 0x08, 0x43, 0x20, 0x85, 0xf8, 0xbd, 0xe9, 0x79, /// 0x1d30 + 0x89, 0x06, 0x89, 0x0f, 0xbd, 0xd1, 0x21, 0x8d, 0x08, 0x22, 0x11, 0x43, 0x21, 0x85, 0xf1, 0x79, /// 0x1d40 + 0x49, 0x1c, 0xca, 0xb2, 0xaa, 0x73, 0x19, 0x46, 0xfe, 0xf7, 0x0a, 0xfe, 0xe8, 0x79, 0x20, 0x21, /// 0x1d50 + 0x08, 0x43, 0xe8, 0x71, 0x08, 0x46, 0xfe, 0xf7, 0x1c, 0xfd, 0xf8, 0xbd, 0xf8, 0xb5, 0xa0, 0x4c, /// 0x1d60 + 0x61, 0x7b, 0x22, 0x7b, 0x26, 0x46, 0x20, 0x3e, 0xe0, 0x79, 0x91, 0x42, 0x07, 0xd3, 0x32, 0x8d, /// 0x1d70 + 0x80, 0x21, 0x8a, 0x43, 0xf7, 0x21, 0x32, 0x85, 0x08, 0x40, 0xe0, 0x71, 0xf8, 0xbd, 0x52, 0x1a, /// 0x1d80 + 0xd5, 0xb2, 0x08, 0x2d, 0x00, 0xd9, 0x08, 0x25, 0x2a, 0x07, 0x13, 0x0e, 0x82, 0x07, 0x01, 0xd5, /// 0x1d90 + 0x07, 0x22, 0x00, 0xe0, 0x06, 0x22, 0x1a, 0x43, 0x02, 0x23, 0x58, 0x40, 0xe0, 0x71, 0x91, 0x4f, /// 0x1da0 + 0x91, 0x48, 0x20, 0x37, 0x09, 0x18, 0x3a, 0x72, 0x38, 0x46, 0x2a, 0x46, 0x09, 0x30, 0xfe, 0xf7, /// 0x1db0 + 0xd7, 0xfd, 0x60, 0x7b, 0x80, 0x21, 0x40, 0x19, 0x60, 0x73, 0x30, 0x8d, 0x08, 0x43, 0x30, 0x85, /// 0x1dc0 + 0x38, 0x46, 0x32, 0x21, 0xa0, 0x38, 0x41, 0x66, 0x05, 0x20, 0x38, 0x77, 0xf8, 0xbd, 0xfe, 0xb5, /// 0x1dd0 + 0x07, 0x46, 0x84, 0x48, 0x20, 0x30, 0x00, 0x90, 0xc0, 0x7f, 0x00, 0x28, 0x06, 0xd1, 0x00, 0x2f, /// 0x1de0 + 0x01, 0xd0, 0x02, 0x20, 0x00, 0xe0, 0x08, 0x20, 0x00, 0x99, 0xc8, 0x77, 0x00, 0x98, 0x7e, 0x4b, /// 0x1df0 + 0xc1, 0x7f, 0xf8, 0x01, 0x86, 0x46, 0x7a, 0x48, 0xde, 0x1d, 0xff, 0x36, 0x20, 0x30, 0xfa, 0x36, /// 0x1e00 + 0x00, 0x89, 0x34, 0x8a, 0x01, 0x94, 0x09, 0x24, 0xa4, 0x01, 0x1c, 0x19, 0x33, 0x7d, 0x8a, 0x07, /// 0x1e10 + 0xa5, 0x79, 0x9c, 0x46, 0x00, 0x2a, 0x4b, 0xd0, 0x62, 0x46, 0x52, 0x08, 0x73, 0x46, 0x1a, 0x43, /// 0x1e20 + 0xd2, 0xb2, 0x32, 0x75, 0x00, 0x2d, 0x0a, 0xd0, 0x07, 0x2d, 0x10, 0xd3, 0xff, 0x2a, 0x11, 0xd0, /// 0x1e30 + 0x00, 0x2a, 0x38, 0xd0, 0x55, 0x2a, 0x38, 0xd0, 0xaa, 0x2a, 0x36, 0xd0, 0x83, 0xe0, 0x48, 0x21, /// 0x1e40 + 0x48, 0x43, 0x6b, 0x49, 0xff, 0xf7, 0x12, 0xfb, 0x01, 0x99, 0x40, 0x18, 0x70, 0x82, 0x6d, 0x1c, /// 0x1e50 + 0xa5, 0x71, 0x82, 0xe0, 0x88, 0x07, 0x02, 0xd5, 0xff, 0xf7, 0x80, 0xff, 0x73, 0xe0, 0x60, 0x4d, /// 0x1e60 + 0x20, 0x3d, 0x6a, 0x8d, 0x00, 0x2a, 0x1c, 0xd0, 0xd0, 0x07, 0x02, 0xd0, 0xff, 0xf7, 0xc3, 0xfe, /// 0x1e70 + 0x11, 0xe0, 0x5b, 0x48, 0x93, 0x06, 0xc1, 0x79, 0x00, 0x2b, 0x07, 0xda, 0x00, 0x22, 0x42, 0x73, /// 0x1e80 + 0xfd, 0x22, 0x11, 0x40, 0xc1, 0x71, 0xff, 0xf7, 0x69, 0xff, 0x04, 0xe0, 0xd2, 0x06, 0x02, 0xd5, /// 0x1e90 + 0xf7, 0x22, 0x11, 0x40, 0xc1, 0x71, 0x28, 0x8d, 0x69, 0x8d, 0x88, 0x43, 0x28, 0x85, 0x00, 0x20, /// 0x1ea0 + 0x68, 0x85, 0x01, 0x20, 0x02, 0xe0, 0x02, 0x20, 0x00, 0xe0, 0x04, 0x20, 0x20, 0x70, 0x4a, 0xe0, /// 0x1eb0 + 0xc9, 0x06, 0x49, 0x0f, 0x47, 0xd0, 0x4b, 0x4a, 0x40, 0x32, 0xd1, 0x79, 0x52, 0x79, 0x00, 0x2d, /// 0x1ec0 + 0x13, 0xd0, 0x48, 0x48, 0x14, 0x30, 0x09, 0x2d, 0x25, 0xd0, 0x0a, 0x2d, 0x3d, 0xd3, 0x00, 0x2f, /// 0x1ed0 + 0x39, 0xd0, 0x00, 0x23, 0xa3, 0x71, 0x00, 0x2a, 0x25, 0xd0, 0x8a, 0x42, 0x27, 0xd9, 0x89, 0x1c, /// 0x1ee0 + 0xfe, 0xf7, 0x93, 0xfd, 0x00, 0x28, 0x26, 0xd0, 0x2d, 0xe0, 0x00, 0x2f, 0x2b, 0xd1, 0x01, 0x23, /// 0x1ef0 + 0xa3, 0x71, 0x00, 0x2a, 0x0c, 0xd0, 0x8a, 0x1a, 0x58, 0x21, 0x92, 0x1c, 0x4a, 0x43, 0x08, 0x32, /// 0x1f00 + 0x50, 0x43, 0x3b, 0x49, 0xff, 0xf7, 0xb2, 0xfa, 0x01, 0x99, 0x40, 0x18, 0x70, 0x82, 0x24, 0xe0, /// 0x1f10 + 0x60, 0x21, 0x48, 0x43, 0xf5, 0xe7, 0x0a, 0x21, 0xa1, 0x71, 0x10, 0x5c, 0xfe, 0xf7, 0x7e, 0xfd, /// 0x1f20 + 0xb8, 0x42, 0x10, 0xd0, 0x19, 0xe0, 0x60, 0x46, 0xff, 0xf7, 0x30, 0xfe, 0xe0, 0x71, 0x60, 0x79, /// 0x1f30 + 0x40, 0x1c, 0x60, 0x71, 0x11, 0xe0, 0x00, 0x98, 0xc0, 0x7f, 0x40, 0x07, 0x01, 0xd5, 0x08, 0x20, /// 0x1f40 + 0xb4, 0xe7, 0xff, 0xf7, 0x66, 0xfe, 0x01, 0x20, 0xfe, 0xbd, 0x11, 0x5c, 0x73, 0x46, 0x49, 0x08, /// 0x1f50 + 0x19, 0x43, 0x11, 0x54, 0xa0, 0x79, 0x40, 0x1c, 0xa0, 0x71, 0x00, 0x20, 0xfe, 0xbd, 0xfe, 0xb5, /// 0x1f60 + 0x20, 0x4c, 0x24, 0x48, 0xa1, 0x89, 0x26, 0x46, 0x00, 0x27, 0x40, 0x3e, 0x81, 0x42, 0x09, 0xd1, /// 0x1f70 + 0x60, 0x8a, 0x41, 0x1e, 0x61, 0x82, 0x03, 0xd3, 0x30, 0x7b, 0x40, 0x1e, 0xf0, 0x72, 0xed, 0xe0, /// 0x1f80 + 0xf7, 0x72, 0xeb, 0xe0, 0x16, 0x48, 0x22, 0x8a, 0x20, 0x38, 0x01, 0x46, 0x15, 0x4d, 0x40, 0x31, /// 0x1f90 + 0x80, 0x30, 0x40, 0x35, 0x01, 0x91, 0x00, 0x90, 0x00, 0x2a, 0x06, 0xd1, 0x2f, 0x70, 0x6f, 0x71, /// 0x1fa0 + 0xaf, 0x71, 0x0f, 0x20, 0x60, 0x82, 0xfe, 0xf7, 0x70, 0xfc, 0x9b, 0xe0, 0x41, 0x00, 0x0e, 0x4a, /// 0x1fb0 + 0x40, 0x1c, 0x89, 0x18, 0xff, 0x31, 0xc1, 0x31, 0x00, 0x07, 0x09, 0x8d, 0x00, 0x0f, 0x60, 0x72, /// 0x1fc0 + 0xa0, 0x89, 0x40, 0x1c, 0x80, 0xb2, 0xa0, 0x81, 0x03, 0x28, 0x2f, 0xd8, 0x01, 0x28, 0x13, 0xd0, /// 0x1fd0 + 0xe2, 0x89, 0x51, 0x18, 0x89, 0xb2, 0xe1, 0x81, 0x03, 0x28, 0x12, 0xd1, 0x12, 0xe0, 0x00, 0x00, /// 0x1fe0 + 0x20, 0x00, 0x00, 0x20, 0x30, 0x03, 0x00, 0x20, 0x30, 0x01, 0x00, 0x20, 0xb0, 0x01, 0x00, 0x20, /// 0x1ff0 + 0x70, 0x17, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0xe7, 0x81, 0xef, 0x70, 0xaf, 0x70, 0xaf, 0x72, /// 0x2000 + 0xef, 0x72, 0x6f, 0xe0, 0x49, 0x1c, 0x48, 0x08, 0xe0, 0x81, 0x01, 0x99, 0x08, 0x81, 0x00, 0x99, /// 0x2010 + 0x09, 0x78, 0xc9, 0x07, 0x01, 0xd1, 0xfe, 0xf7, 0xe1, 0xf9, 0xe1, 0x89, 0x50, 0x4a, 0x48, 0x08, /// 0x2020 + 0x80, 0x18, 0xff, 0xf7, 0x23, 0xfa, 0x01, 0x99, 0xc8, 0x83, 0x5b, 0xe0, 0x00, 0x98, 0xc2, 0x7a, /// 0x2030 + 0x06, 0x20, 0x93, 0x07, 0x9b, 0x0f, 0x98, 0x40, 0x80, 0x1e, 0x52, 0x07, 0xe2, 0x89, 0x03, 0xd5, /// 0x2040 + 0x10, 0x18, 0x88, 0x42, 0x03, 0xd3, 0x20, 0xe0, 0x10, 0x1a, 0x88, 0x42, 0x1d, 0xd9, 0xe8, 0x78, /// 0x2050 + 0x40, 0x1c, 0xc0, 0xb2, 0xe8, 0x70, 0x0a, 0x28, 0x53, 0xd8, 0xa8, 0x7a, 0x00, 0x28, 0x12, 0xd0, /// 0x2060 + 0xa8, 0x78, 0x05, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x05, 0xe0, 0x02, 0x28, 0x0b, 0xd9, 0xe8, 0x7a, /// 0x2070 + 0x00, 0x28, 0x06, 0xd0, 0x01, 0x20, 0xff, 0xf7, 0xaa, 0xfe, 0x00, 0x28, 0x41, 0xd1, 0xef, 0x72, /// 0x2080 + 0x01, 0xe0, 0x01, 0x20, 0xe8, 0x72, 0xaf, 0x70, 0x2c, 0xe0, 0xa8, 0x78, 0x40, 0x1c, 0xc0, 0xb2, /// 0x2090 + 0xa8, 0x70, 0xa9, 0x7a, 0x00, 0x29, 0x0c, 0xd0, 0xe9, 0x7a, 0x00, 0x29, 0x03, 0xd0, 0x05, 0x28, /// 0x20a0 + 0x0c, 0xd9, 0x01, 0x20, 0x02, 0xe0, 0x0a, 0x28, 0x08, 0xd9, 0x00, 0x20, 0xff, 0xf7, 0x8f, 0xfe, /// 0x20b0 + 0x27, 0xe0, 0xe8, 0x78, 0x02, 0x28, 0x01, 0xd9, 0x01, 0x20, 0xa8, 0x72, 0xe8, 0x78, 0x05, 0x28, /// 0x20c0 + 0x01, 0xd9, 0x00, 0x20, 0x05, 0xe0, 0x02, 0x28, 0x0b, 0xd9, 0xe8, 0x7a, 0x00, 0x28, 0x06, 0xd0, /// 0x20d0 + 0x01, 0x20, 0xff, 0xf7, 0x7c, 0xfe, 0x00, 0x28, 0x13, 0xd1, 0xef, 0x72, 0x01, 0xe0, 0x01, 0x20, /// 0x20e0 + 0xe8, 0x72, 0xef, 0x70, 0x21, 0x7a, 0x60, 0x7a, 0x81, 0x42, 0x00, 0xd0, 0x5e, 0xe7, 0x30, 0x7b, /// 0x20f0 + 0x40, 0x1e, 0xf0, 0x72, 0x20, 0x8a, 0x40, 0x1c, 0x80, 0xb2, 0x20, 0x82, 0x61, 0x8a, 0x88, 0x42, /// 0x2100 + 0x2c, 0xd9, 0xfe, 0xf7, 0x54, 0xfb, 0x00, 0x20, 0xc0, 0x43, 0xa0, 0x81, 0x15, 0x48, 0xc7, 0x77, /// 0x2110 + 0x70, 0x7c, 0x00, 0x28, 0x01, 0xd0, 0x16, 0x20, 0x00, 0xe0, 0x05, 0x20, 0x70, 0x74, 0x28, 0x78, /// 0x2120 + 0x00, 0x28, 0x01, 0xd0, 0x70, 0x7c, 0x10, 0xe0, 0x60, 0x8a, 0x0f, 0x28, 0x04, 0xd9, 0x21, 0x8a, /// 0x2130 + 0x40, 0x1a, 0x71, 0x7c, 0x40, 0x18, 0x08, 0xe0, 0x20, 0x8a, 0x31, 0x7b, 0x02, 0x1d, 0x8a, 0x42, /// 0x2140 + 0x02, 0xd2, 0xc0, 0xb2, 0x08, 0x1a, 0x00, 0xe0, 0x04, 0x20, 0x60, 0x82, 0x20, 0x8a, 0x61, 0x8a, /// 0x2150 + 0x42, 0x18, 0x31, 0x7b, 0x8a, 0x42, 0x01, 0xd2, 0x08, 0x1a, 0x60, 0x82, 0x00, 0x20, 0xfe, 0xbd, /// 0x2160 + 0x00, 0xdc, 0x05, 0x00, 0x50, 0x03, 0x00, 0x20, 0x10, 0xb5, 0xfe, 0x48, 0x41, 0x7b, 0x0a, 0x07, /// 0x2170 + 0x03, 0xd5, 0xf7, 0x22, 0x11, 0x40, 0x41, 0x73, 0x10, 0xbd, 0x08, 0x22, 0x11, 0x43, 0x41, 0x73, /// 0x2180 + 0xfe, 0xf7, 0x18, 0xfd, 0x10, 0xbd, 0xf7, 0x49, 0x00, 0x20, 0xf7, 0x4a, 0x40, 0x31, 0x89, 0x6e, /// 0x2190 + 0x92, 0x68, 0x06, 0xe0, 0x0b, 0x46, 0x53, 0x40, 0x1b, 0x06, 0x00, 0xd0, 0x40, 0x1c, 0x09, 0x0a, /// 0x21a0 + 0x12, 0x0a, 0x0b, 0x46, 0x13, 0x43, 0xf5, 0xd1, 0x70, 0x47, 0xee, 0x4a, 0x10, 0xb5, 0xef, 0x4b, /// 0x21b0 + 0x40, 0x3a, 0x93, 0x85, 0x20, 0x32, 0x90, 0x73, 0xd1, 0x73, 0x11, 0x46, 0x01, 0x20, 0x80, 0x31, /// 0x21c0 + 0xc8, 0x77, 0x02, 0x20, 0xfe, 0xf7, 0x8d, 0xfc, 0x10, 0xbd, 0xe6, 0x49, 0x10, 0xb5, 0xe8, 0x4a, /// 0x21d0 + 0x40, 0x39, 0x8a, 0x85, 0x20, 0x31, 0x88, 0x73, 0x04, 0x20, 0x80, 0x31, 0xc8, 0x77, 0x01, 0x20, /// 0x21e0 + 0xfe, 0xf7, 0x7f, 0xfc, 0x10, 0xbd, 0xf8, 0xb5, 0x09, 0x21, 0xe2, 0x4b, 0xdd, 0x4c, 0x89, 0x01, /// 0x21f0 + 0x5d, 0x18, 0xa0, 0x34, 0xff, 0x33, 0xe0, 0x79, 0xff, 0x33, 0x02, 0x26, 0xda, 0x4a, 0x02, 0x33, /// 0x2200 + 0x00, 0x28, 0x02, 0xd0, 0x01, 0x28, 0x0b, 0xd0, 0x3e, 0xe0, 0xd0, 0x79, 0xc0, 0x07, 0x05, 0xd0, /// 0x2210 + 0x31, 0x20, 0xff, 0xf7, 0xda, 0xff, 0x01, 0x20, 0xe0, 0x71, 0xf8, 0xbd, 0xe6, 0x71, 0x0c, 0xe0, /// 0x2220 + 0x28, 0x78, 0x00, 0x07, 0xfa, 0xd5, 0x18, 0x7d, 0x31, 0x28, 0xf7, 0xd1, 0x58, 0x7d, 0x10, 0x71, /// 0x2230 + 0x98, 0x7d, 0x50, 0x71, 0xd8, 0x7d, 0x90, 0x71, 0xf0, 0xe7, 0xe7, 0x79, 0x78, 0x08, 0xf9, 0x07, /// 0x2240 + 0x7f, 0x1c, 0xff, 0xb2, 0xe7, 0x71, 0xbc, 0x46, 0xc7, 0x4f, 0x80, 0x3f, 0x00, 0x29, 0x0c, 0xd0, /// 0x2250 + 0x29, 0x78, 0xc9, 0x07, 0x18, 0xd0, 0x39, 0x18, 0xc6, 0x4f, 0x80, 0x31, 0x38, 0x18, 0x13, 0x27, /// 0x2260 + 0x7f, 0x01, 0x09, 0x7b, 0xc0, 0x19, 0x01, 0x72, 0x0e, 0xe0, 0x3f, 0x18, 0x80, 0x37, 0x39, 0x7b, /// 0x2270 + 0x3f, 0x7a, 0xb9, 0x42, 0x05, 0xd0, 0xc2, 0x07, 0x00, 0xd1, 0x04, 0x20, 0xff, 0xf7, 0x95, 0xff, /// 0x2280 + 0xf8, 0xbd, 0x60, 0x46, 0x40, 0x1c, 0xe0, 0x71, 0xe0, 0x79, 0x08, 0x28, 0xd5, 0xd3, 0x41, 0x1c, /// 0x2290 + 0xe1, 0x71, 0x08, 0x28, 0x06, 0xd0, 0x28, 0x78, 0xc0, 0x07, 0x08, 0xd0, 0x98, 0x6e, 0x90, 0x60, /// 0x22a0 + 0xd6, 0x71, 0x06, 0xe0, 0xff, 0xf7, 0x6f, 0xff, 0xc1, 0xb2, 0x00, 0x20, 0xe6, 0xe7, 0x04, 0x20, /// 0x22b0 + 0xd0, 0x71, 0xac, 0x48, 0x05, 0x21, 0x80, 0x38, 0x81, 0x72, 0xf8, 0xbd, 0xa9, 0x48, 0x10, 0xb5, /// 0x22c0 + 0xad, 0x49, 0x40, 0x38, 0xc1, 0x62, 0xa7, 0x49, 0x01, 0x20, 0x60, 0x31, 0xc8, 0x77, 0xfe, 0xf7, /// 0x22d0 + 0x08, 0xfc, 0x10, 0xbd, 0xa3, 0x48, 0x10, 0xb5, 0xa8, 0x49, 0x40, 0x38, 0x81, 0x85, 0xa2, 0x48, /// 0x22e0 + 0x60, 0x38, 0x81, 0x7e, 0x9f, 0x48, 0x20, 0x38, 0x81, 0x73, 0x01, 0x20, 0xfe, 0xf7, 0xf9, 0xfb, /// 0x22f0 + 0x10, 0xbd, 0x9c, 0x48, 0x10, 0xb5, 0x60, 0x30, 0x00, 0x7a, 0xff, 0xf7, 0x47, 0xfc, 0x99, 0x49, /// 0x2300 + 0xc4, 0xb2, 0x68, 0x31, 0x08, 0x46, 0x62, 0x1c, 0x7b, 0x38, 0xfe, 0xf7, 0x29, 0xfb, 0x95, 0x48, /// 0x2310 + 0x0c, 0x21, 0x20, 0x38, 0x01, 0x73, 0x20, 0x46, 0xfe, 0xf7, 0xe3, 0xfb, 0x10, 0xbd, 0x91, 0x49, /// 0x2320 + 0x10, 0xb5, 0x0c, 0x22, 0x20, 0x39, 0x0a, 0x73, 0x15, 0x22, 0x4a, 0x73, 0x88, 0x73, 0x01, 0x20, /// 0x2330 + 0xfe, 0xf7, 0xd7, 0xfb, 0x10, 0xbd, 0x10, 0xb5, 0x8e, 0x48, 0x00, 0x78, 0xff, 0xf7, 0x26, 0xfc, /// 0x2340 + 0x04, 0x46, 0x42, 0x1c, 0x87, 0x48, 0x8b, 0x49, 0x13, 0x38, 0xfe, 0xf7, 0x09, 0xfb, 0x85, 0x48, /// 0x2350 + 0x0c, 0x21, 0x20, 0x38, 0x01, 0x73, 0x20, 0x46, 0xfe, 0xf7, 0xc3, 0xfb, 0x10, 0xbd, 0xf0, 0xb5, /// 0x2360 + 0x81, 0x48, 0x01, 0x78, 0x49, 0x06, 0x01, 0xd5, 0x00, 0x20, 0xf0, 0xbd, 0x01, 0x8a, 0x7e, 0x48, /// 0x2370 + 0x40, 0x38, 0x00, 0x88, 0x0b, 0x1a, 0x02, 0xd5, 0x01, 0x25, 0x59, 0x42, 0x01, 0xe0, 0x00, 0x25, /// 0x2380 + 0x19, 0x46, 0x78, 0x48, 0x04, 0x26, 0xa0, 0x30, 0x42, 0x7c, 0x94, 0x08, 0x34, 0x1b, 0x4c, 0x43, /// 0x2390 + 0x61, 0x09, 0x05, 0xd0, 0x00, 0x2d, 0x01, 0xd0, 0x00, 0x24, 0x02, 0xe0, 0x02, 0x24, 0x00, 0xe0, /// 0x23a0 + 0x01, 0x24, 0x10, 0x26, 0x86, 0x57, 0x02, 0x27, 0x7e, 0x40, 0x20, 0x27, 0xa6, 0x42, 0x05, 0xd1, /// 0x23b0 + 0x0f, 0x2a, 0x01, 0xd2, 0x52, 0x1c, 0x0e, 0xe0, 0x87, 0x74, 0x0e, 0xe0, 0x86, 0x7c, 0x00, 0x2e, /// 0x23c0 + 0x0b, 0xd0, 0x76, 0x1e, 0x36, 0x06, 0x36, 0x0e, 0x86, 0x74, 0x06, 0xd1, 0x00, 0x2a, 0x04, 0xd0, /// 0x23d0 + 0xfc, 0x26, 0x52, 0x1e, 0x32, 0x40, 0x42, 0x74, 0xee, 0xe7, 0x04, 0x74, 0x00, 0x24, 0x00, 0x29, /// 0x23e0 + 0x0b, 0xd0, 0xc4, 0x73, 0x84, 0x73, 0x08, 0x22, 0x02, 0x73, 0x7f, 0x29, 0x00, 0xd9, 0x7f, 0x21, /// 0x23f0 + 0x00, 0x2d, 0x00, 0xd0, 0x49, 0x42, 0x48, 0xb2, 0xf0, 0xbd, 0x82, 0x7b, 0xd2, 0x18, 0x56, 0xb2, /// 0x2400 + 0x86, 0x73, 0xc2, 0x7b, 0x52, 0x1c, 0xd3, 0xb2, 0xc3, 0x73, 0x9a, 0x07, 0xf0, 0xd1, 0x02, 0x7b, /// 0x2410 + 0x96, 0x42, 0x02, 0xdd, 0x01, 0x21, 0x00, 0x25, 0x04, 0xe0, 0x57, 0x42, 0xbe, 0x42, 0x07, 0xda, /// 0x2420 + 0x01, 0x21, 0x0d, 0x46, 0x0c, 0x2b, 0x01, 0xd3, 0x52, 0x1c, 0x02, 0x73, 0x84, 0x73, 0xdc, 0xe7, /// 0x2430 + 0xc4, 0x73, 0x43, 0x7b, 0x5b, 0x1c, 0xdb, 0xb2, 0x43, 0x73, 0x20, 0x2b, 0xf6, 0xd9, 0x44, 0x73, /// 0x2440 + 0x04, 0x2a, 0xf3, 0xd9, 0x52, 0x1e, 0xf0, 0xe7, 0xfe, 0xb5, 0x47, 0x48, 0x4c, 0x49, 0x80, 0x38, /// 0x2450 + 0x80, 0x8f, 0x45, 0x4e, 0x48, 0x43, 0x00, 0x0c, 0x40, 0x3e, 0xb0, 0x87, 0x30, 0x88, 0x41, 0x43, /// 0x2460 + 0x09, 0x0c, 0xf1, 0x87, 0x47, 0x49, 0x88, 0x42, 0x05, 0xd2, 0x47, 0x48, 0x01, 0x8b, 0x1f, 0x22, /// 0x2470 + 0x12, 0x02, 0x91, 0x43, 0x01, 0x83, 0x3b, 0x4f, 0x3e, 0x4d, 0x78, 0x7b, 0x3a, 0x4c, 0x41, 0x07, /// 0x2480 + 0xe8, 0x1d, 0xf9, 0x30, 0x80, 0x3c, 0x01, 0x90, 0x20, 0x46, 0x80, 0x30, 0xff, 0x35, 0xa0, 0x34, /// 0x2490 + 0x81, 0x35, 0x00, 0x90, 0x00, 0x29, 0x4e, 0xda, 0x70, 0x8f, 0xfe, 0xf7, 0x75, 0xf8, 0xb0, 0x80, /// 0x24a0 + 0x00, 0x99, 0x09, 0x78, 0xc9, 0x07, 0x2b, 0xd1, 0xfe, 0xf7, 0x1a, 0xfc, 0xb8, 0x7b, 0xfe, 0xf7, /// 0x24b0 + 0x14, 0xf8, 0xb9, 0x7b, 0x35, 0x4a, 0x04, 0x29, 0x02, 0xd2, 0x01, 0x20, 0x90, 0x80, 0x03, 0xe0, /// 0x24c0 + 0x03, 0x20, 0x90, 0x80, 0x0a, 0x29, 0x01, 0xd2, 0x00, 0x20, 0x08, 0xe0, 0x0f, 0x29, 0x01, 0xd2, /// 0x24d0 + 0x01, 0x20, 0x04, 0xe0, 0x14, 0x29, 0x01, 0xd2, 0x02, 0x20, 0x00, 0xe0, 0x03, 0x20, 0x2b, 0x4a, /// 0x24e0 + 0x12, 0x88, 0xf0, 0x23, 0x9a, 0x43, 0x80, 0x01, 0x02, 0x43, 0x28, 0x48, 0x02, 0x80, 0x07, 0x29, /// 0x24f0 + 0x01, 0xd9, 0x16, 0x21, 0x00, 0xe0, 0x06, 0x21, 0x24, 0x48, 0x81, 0x81, 0xfe, 0xf7, 0xc0, 0xfb, /// 0x2500 + 0xff, 0xf7, 0x2d, 0xff, 0x18, 0x49, 0x40, 0x31, 0x0a, 0x79, 0x94, 0x46, 0x92, 0x07, 0x6b, 0xd1, /// 0x2510 + 0x8b, 0x79, 0x5a, 0x1c, 0x8a, 0x71, 0x03, 0x2b, 0x66, 0xd9, 0x72, 0x7b, 0x12, 0x07, 0x63, 0xd4, /// 0x2520 + 0x62, 0x46, 0x06, 0x23, 0x1a, 0x43, 0x0a, 0x71, 0x01, 0x9a, 0x13, 0x68, 0x00, 0x9a, 0x93, 0x64, /// 0x2530 + 0x00, 0x22, 0x4a, 0x71, 0x58, 0xe0, 0xff, 0xf7, 0x12, 0xff, 0x79, 0x7b, 0x0a, 0x07, 0x53, 0xd4, /// 0x2540 + 0x00, 0x9a, 0x13, 0x8a, 0x0d, 0x4a, 0xaa, 0x32, 0x93, 0x42, 0x28, 0xd8, 0x32, 0x88, 0x9a, 0x42, /// 0x2550 + 0x06, 0xd8, 0x01, 0x9a, 0x13, 0x68, 0x2a, 0x6e, 0x9a, 0x1a, 0x0d, 0x4b, 0x9a, 0x42, 0x1c, 0xdb, /// 0x2560 + 0x22, 0x7a, 0x17, 0xe0, 0xf0, 0x02, 0x00, 0x20, 0x80, 0x00, 0x00, 0x20, 0x0c, 0x20, 0x00, 0x00, /// 0x2570 + 0x0c, 0x07, 0x00, 0x00, 0x30, 0x01, 0x00, 0x20, 0x0c, 0x09, 0x00, 0x00, 0x0c, 0x05, 0x00, 0x00, /// 0x2580 + 0x80, 0x20, 0x05, 0x00, 0x83, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, 0x00, 0x34, 0x00, 0x40, /// 0x2590 + 0x88, 0x13, 0x00, 0x00, 0x10, 0x23, 0x1a, 0x43, 0x11, 0xe0, 0x37, 0x20, 0x10, 0xe0, 0x22, 0x7a, /// 0x25a0 + 0x94, 0x46, 0x93, 0x07, 0x06, 0xd5, 0x01, 0x9b, 0x2a, 0x6e, 0x1b, 0x68, 0x9b, 0x1a, 0xfe, 0x4a, /// 0x25b0 + 0x93, 0x42, 0x19, 0xdb, 0x62, 0x46, 0x10, 0x23, 0x1a, 0x43, 0x52, 0x08, 0x52, 0x00, 0x22, 0x72, /// 0x25c0 + 0x22, 0x7a, 0x93, 0x07, 0x10, 0xd4, 0xd3, 0x06, 0x0e, 0xd5, 0x10, 0x07, 0x02, 0xd5, 0xf8, 0x48, /// 0x25d0 + 0xf6, 0x4a, 0x42, 0x81, 0x07, 0x20, 0x01, 0x43, 0x79, 0x73, 0x32, 0x20, 0x68, 0x66, 0x01, 0x98, /// 0x25e0 + 0x00, 0x68, 0x28, 0x38, 0xa8, 0x65, 0xfe, 0xbd, 0xf1, 0x49, 0x42, 0x1d, 0x20, 0x31, 0x0a, 0x2a, /// 0x25f0 + 0x02, 0xd9, 0x7a, 0x7b, 0x12, 0x07, 0x0a, 0xd5, 0x00, 0x22, 0x8a, 0x77, 0x0a, 0x7f, 0x00, 0x2a, /// 0x2600 + 0x02, 0xd0, 0x52, 0x1e, 0x0a, 0x77, 0x09, 0xe0, 0x96, 0x21, 0x69, 0x66, 0x06, 0xe0, 0x32, 0x22, /// 0x2610 + 0x6a, 0x66, 0x8a, 0x7f, 0xff, 0x2a, 0x01, 0xd0, 0x52, 0x1c, 0x8a, 0x77, 0x21, 0x7a, 0x0a, 0x07, /// 0x2620 + 0x11, 0xd5, 0x82, 0x1d, 0x0c, 0x2a, 0x04, 0xd8, 0x8a, 0x07, 0x09, 0xd5, 0x49, 0x08, 0x49, 0x00, /// 0x2630 + 0x08, 0xe0, 0xdf, 0x4a, 0x80, 0x32, 0x52, 0x7d, 0x03, 0x2a, 0x04, 0xd9, 0x8a, 0x07, 0x02, 0xd4, /// 0x2640 + 0xfb, 0x22, 0x11, 0x40, 0x21, 0x72, 0xb1, 0x88, 0x32, 0x29, 0x15, 0xd2, 0x1e, 0x28, 0x03, 0xdd, /// 0x2650 + 0x00, 0x99, 0x49, 0x8c, 0x27, 0x29, 0x04, 0xd0, 0x00, 0x99, 0x49, 0x8c, 0x28, 0x29, 0x02, 0xd0, /// 0x2660 + 0x0a, 0xe0, 0x1e, 0x20, 0x08, 0xe0, 0x09, 0x21, 0xc9, 0x43, 0x0a, 0x28, 0x01, 0xdd, 0x0a, 0x20, /// 0x2670 + 0x02, 0xe0, 0x88, 0x42, 0x00, 0xda, 0x08, 0x46, 0xc3, 0x21, 0x89, 0x00, 0xa9, 0x85, 0xcc, 0x49, /// 0x2680 + 0x60, 0x39, 0x88, 0x73, 0x00, 0x28, 0x01, 0xd0, 0x01, 0x20, 0x78, 0x74, 0x01, 0x20, 0xfe, 0xf7, /// 0x2690 + 0x28, 0xfa, 0xc8, 0x48, 0x01, 0x8c, 0x49, 0x1c, 0x01, 0x84, 0xfe, 0xbd, 0xc4, 0x48, 0x10, 0xb5, /// 0x26a0 + 0x0c, 0x21, 0x60, 0x38, 0x01, 0x73, 0x38, 0x21, 0x41, 0x73, 0x0a, 0x21, 0x81, 0x73, 0xc1, 0x49, /// 0x26b0 + 0x40, 0x31, 0x09, 0x8f, 0xc1, 0x73, 0x09, 0x0a, 0x01, 0x74, 0xbd, 0x49, 0x10, 0x20, 0x20, 0x31, /// 0x26c0 + 0xc8, 0x77, 0x03, 0x20, 0xfe, 0xf7, 0x0d, 0xfa, 0x10, 0xbd, 0xb9, 0x48, 0x10, 0xb5, 0x0c, 0x21, /// 0x26d0 + 0x60, 0x38, 0x01, 0x73, 0x38, 0x21, 0x41, 0x73, 0x3b, 0x21, 0x81, 0x73, 0x02, 0x21, 0xc1, 0x73, /// 0x26e0 + 0xbb, 0x21, 0x01, 0x74, 0xb2, 0x49, 0x10, 0x20, 0x20, 0x31, 0xc8, 0x77, 0x03, 0x20, 0xfe, 0xf7, /// 0x26f0 + 0xf8, 0xf9, 0x10, 0xbd, 0xae, 0x4a, 0x10, 0xb5, 0x0c, 0x23, 0x60, 0x3a, 0x13, 0x73, 0xa4, 0x23, /// 0x2700 + 0x53, 0x73, 0x90, 0x73, 0xaa, 0x48, 0x08, 0x22, 0x51, 0x38, 0xfe, 0xf7, 0x29, 0xf9, 0xa8, 0x49, /// 0x2710 + 0x10, 0x20, 0x20, 0x31, 0xc8, 0x77, 0x0c, 0x20, 0xfe, 0xf7, 0xe3, 0xf9, 0x10, 0xbd, 0x10, 0xb5, /// 0x2720 + 0xa5, 0xa1, 0x03, 0xc9, 0xa2, 0xb0, 0x01, 0x91, 0xa2, 0x49, 0x00, 0x90, 0x14, 0x31, 0x08, 0x22, /// 0x2730 + 0x0c, 0x46, 0x1c, 0xa8, 0xfe, 0xf7, 0x14, 0xf9, 0x08, 0x22, 0x69, 0x46, 0x1e, 0xa8, 0xfe, 0xf7, /// 0x2740 + 0x0f, 0xf9, 0x02, 0xa8, 0xfe, 0xf7, 0xe6, 0xfc, 0x10, 0x22, 0x1c, 0xa9, 0x02, 0xa8, 0xfe, 0xf7, /// 0x2750 + 0x27, 0xfe, 0x98, 0x49, 0x02, 0xa8, 0xb0, 0x31, 0xfe, 0xf7, 0xf4, 0xfd, 0x21, 0x46, 0x08, 0x20, /// 0x2760 + 0xff, 0xf7, 0xc8, 0xff, 0x22, 0xb0, 0x10, 0xbd, 0x92, 0x48, 0x10, 0xb5, 0x40, 0x30, 0x00, 0x7c, /// 0x2770 + 0xff, 0xf7, 0x0c, 0xfa, 0x04, 0x46, 0x42, 0x1c, 0x8e, 0x49, 0x8d, 0x48, 0x50, 0x31, 0x53, 0x38, /// 0x2780 + 0xfe, 0xf7, 0xee, 0xf8, 0x8a, 0x48, 0x0c, 0x21, 0x60, 0x38, 0x01, 0x73, 0x88, 0x49, 0x10, 0x20, /// 0x2790 + 0x20, 0x31, 0xc8, 0x77, 0x20, 0x46, 0xfe, 0xf7, 0xa4, 0xf9, 0x10, 0xbd, 0xfe, 0xb5, 0x85, 0x4d, /// 0x27a0 + 0x80, 0x35, 0x28, 0x7e, 0x2e, 0x46, 0x40, 0x1e, 0xc2, 0xb2, 0x20, 0x36, 0x2a, 0x76, 0x00, 0x2a, /// 0x27b0 + 0x1a, 0xd0, 0x80, 0x49, 0x9c, 0x20, 0x40, 0x5a, 0x40, 0x31, 0x00, 0x91, 0x08, 0x2a, 0x42, 0xd3, /// 0x27c0 + 0x91, 0x07, 0x10, 0xd1, 0x00, 0x99, 0x6b, 0x8b, 0x09, 0x88, 0x59, 0x18, 0x89, 0xb2, 0x69, 0x83, /// 0x27d0 + 0x00, 0x9b, 0x5b, 0x8f, 0xc0, 0x18, 0x80, 0xb2, 0xa8, 0x83, 0x08, 0x2a, 0x03, 0xd1, 0x09, 0x09, /// 0x27e0 + 0x69, 0x83, 0x00, 0x09, 0xa8, 0x83, 0xfe, 0xbd, 0x71, 0x48, 0xfd, 0x21, 0x40, 0x30, 0x02, 0x78, /// 0x27f0 + 0x70, 0x48, 0xd3, 0x07, 0xa0, 0x30, 0x00, 0x7a, 0x01, 0x40, 0x00, 0x2b, 0x16, 0xd0, 0x02, 0x07, /// 0x2800 + 0xf1, 0xd5, 0xc2, 0x07, 0x01, 0xd0, 0x40, 0x21, 0x0d, 0xe0, 0x82, 0x07, 0x01, 0xd5, 0x31, 0x72, /// 0x2810 + 0xfe, 0xbd, 0x41, 0x07, 0x06, 0xd4, 0xf7, 0x21, 0x08, 0x40, 0x30, 0x72, 0x64, 0x48, 0x68, 0x49, /// 0x2820 + 0x41, 0x81, 0xfe, 0xbd, 0x80, 0x21, 0x08, 0x43, 0x30, 0x72, 0xfe, 0xbd, 0x92, 0x07, 0xfc, 0xd5, /// 0x2830 + 0x02, 0x07, 0xfa, 0xd5, 0xc2, 0x07, 0xf8, 0xd1, 0x82, 0x07, 0xf6, 0xd5, 0x40, 0x06, 0xf4, 0xd5, /// 0x2840 + 0xbf, 0x20, 0x01, 0x40, 0xe3, 0xe7, 0x06, 0x2a, 0xef, 0xd8, 0xfd, 0xf7, 0x9d, 0xfe, 0x04, 0x46, /// 0x2850 + 0x68, 0x8b, 0x0b, 0x21, 0x09, 0x07, 0x40, 0x18, 0xfe, 0xf7, 0xca, 0xfa, 0x05, 0x20, 0x40, 0x07, /// 0x2860 + 0x20, 0x43, 0xfe, 0xf7, 0xc5, 0xfa, 0x53, 0x48, 0x81, 0x8f, 0x0d, 0x20, 0x00, 0x07, 0x08, 0x18, /// 0x2870 + 0xfe, 0xf7, 0xbe, 0xfa, 0x00, 0x98, 0x0f, 0x21, 0x00, 0x89, 0x09, 0x07, 0x40, 0x18, 0xfe, 0xf7, /// 0x2880 + 0xb7, 0xfa, 0x50, 0x48, 0x00, 0x88, 0x00, 0x0b, 0xc1, 0x07, 0x05, 0xd0, 0x40, 0x07, 0x80, 0x0f, /// 0x2890 + 0x0a, 0x21, 0x40, 0x1c, 0x48, 0x43, 0x04, 0x19, 0x68, 0x8b, 0x15, 0x21, 0x61, 0x43, 0x48, 0x43, /// 0x28a0 + 0x07, 0x0b, 0x00, 0x20, 0x68, 0x83, 0xa8, 0x83, 0x07, 0x21, 0x38, 0x46, 0x49, 0x07, 0x08, 0x43, /// 0x28b0 + 0xfe, 0xf7, 0x9e, 0xfa, 0x44, 0x48, 0x80, 0x8b, 0xc0, 0x07, 0x0a, 0xd0, 0x43, 0x48, 0x81, 0x88, /// 0x28c0 + 0x89, 0x07, 0x89, 0x0f, 0x01, 0x29, 0x06, 0xd0, 0x41, 0x49, 0x8c, 0x42, 0x05, 0xd9, 0x05, 0x20, /// 0x28d0 + 0x07, 0xe0, 0x07, 0x20, 0x05, 0xe0, 0x00, 0x20, 0x03, 0xe0, 0x00, 0x88, 0x00, 0x06, 0x80, 0x0f, /// 0x28e0 + 0x40, 0x1c, 0x68, 0x76, 0x00, 0x06, 0xc1, 0x0d, 0x32, 0x48, 0x09, 0x18, 0x60, 0x31, 0x0a, 0x7a, /// 0x28f0 + 0x7a, 0x43, 0xd3, 0x09, 0x09, 0x22, 0x8a, 0x56, 0x0a, 0x21, 0x4a, 0x43, 0xd4, 0x18, 0x00, 0xd5, /// 0x2900 + 0x00, 0x24, 0x34, 0x4f, 0x84, 0x84, 0x3b, 0x46, 0xff, 0x33, 0x2a, 0x7a, 0x03, 0x21, 0x81, 0x33, /// 0x2910 + 0xff, 0x37, 0x89, 0x07, 0xa1, 0x37, 0x01, 0x93, 0x31, 0x2a, 0x0b, 0xd0, 0x00, 0x22, 0x2a, 0x76, /// 0x2920 + 0x27, 0x4a, 0x80, 0x8f, 0x87, 0x3a, 0x90, 0x42, 0x66, 0xd8, 0x2b, 0x48, 0x84, 0x42, 0x68, 0xd9, /// 0x2930 + 0x04, 0x46, 0x66, 0xe0, 0x1e, 0x4a, 0x01, 0x20, 0x28, 0x76, 0x20, 0x32, 0xd0, 0x77, 0x30, 0x7a, /// 0x2940 + 0x02, 0x07, 0x0a, 0xd5, 0x80, 0x07, 0x01, 0xd5, 0x01, 0x26, 0x18, 0xe0, 0x18, 0x4a, 0x02, 0x26, /// 0x2950 + 0x80, 0x32, 0x50, 0x7d, 0x40, 0x1c, 0x50, 0x75, 0x11, 0xe0, 0x16, 0x4a, 0x00, 0x26, 0xc0, 0x32, /// 0x2960 + 0x10, 0x79, 0x83, 0x07, 0x0b, 0xd1, 0x00, 0x9b, 0x5b, 0x7b, 0x1b, 0x07, 0x07, 0xd5, 0x06, 0x23, /// 0x2970 + 0x18, 0x43, 0x10, 0x71, 0x19, 0x48, 0x00, 0x68, 0xa8, 0x64, 0x00, 0x20, 0x50, 0x71, 0x28, 0x78, /// 0x2980 + 0x00, 0x06, 0x00, 0xd5, 0x64, 0x08, 0x20, 0x46, 0x08, 0x43, 0xfe, 0xf7, 0x31, 0xfa, 0xa9, 0x7a, /// 0x2990 + 0x7d, 0x20, 0xc0, 0x00, 0x41, 0x43, 0x20, 0x04, 0xfe, 0xf7, 0x68, 0xfd, 0x10, 0x49, 0x88, 0x42, /// 0x29a0 + 0x00, 0xd9, 0x08, 0x46, 0x0f, 0x4a, 0x1f, 0xe0, 0x88, 0x13, 0x00, 0x00, 0x6c, 0x07, 0x00, 0x00, /// 0x29b0 + 0x30, 0x03, 0x00, 0x20, 0x00, 0x00, 0x00, 0x20, 0xf9, 0x6e, 0xd4, 0xc1, 0xe3, 0x2a, 0xb7, 0x58, /// 0x29c0 + 0xdc, 0x05, 0x00, 0x00, 0x20, 0x38, 0x00, 0x40, 0x00, 0x30, 0x00, 0x40, 0x00, 0x34, 0x00, 0x40, /// 0x29d0 + 0x52, 0x03, 0x00, 0x00, 0x30, 0x01, 0x00, 0x20, 0xe8, 0x26, 0x00, 0x00, 0x30, 0x02, 0x00, 0x20, /// 0x29e0 + 0xff, 0xff, 0x00, 0x00, 0x0c, 0x31, 0x00, 0x00, 0x01, 0x99, 0x8a, 0x85, 0xbe, 0x73, 0x01, 0x0a, /// 0x29f0 + 0xf9, 0x73, 0x38, 0x74, 0x03, 0x20, 0x11, 0xe0, 0xfe, 0x48, 0x84, 0x42, 0x00, 0xd9, 0x04, 0x46, /// 0x2a00 + 0x64, 0x08, 0x20, 0x46, 0x08, 0x43, 0xfe, 0xf7, 0xf3, 0xf9, 0xe0, 0x01, 0xfa, 0x49, 0xfe, 0xf7, /// 0x2a10 + 0x2d, 0xfd, 0x01, 0x99, 0xf9, 0x4a, 0x8a, 0x85, 0xb8, 0x73, 0x01, 0x20, 0xfe, 0xf7, 0x61, 0xf8, /// 0x2a20 + 0xfe, 0xbd, 0x10, 0xb5, 0xf6, 0x48, 0x01, 0x22, 0x41, 0x7b, 0x49, 0x1e, 0xc9, 0xb2, 0x41, 0x73, /// 0x2a30 + 0x8b, 0x07, 0xf4, 0x48, 0x00, 0x2b, 0x03, 0xda, 0x81, 0x8b, 0x11, 0x43, 0x81, 0x83, 0x10, 0xbd, /// 0x2a40 + 0xcb, 0x07, 0xf1, 0x49, 0x0c, 0xd0, 0x03, 0x8b, 0x8b, 0x43, 0x09, 0x21, 0x09, 0x02, 0x59, 0x18, /// 0x2a50 + 0x01, 0x83, 0xee, 0x48, 0x82, 0x80, 0x01, 0x88, 0x30, 0x22, 0x91, 0x43, 0x01, 0x80, 0x10, 0xbd, /// 0x2a60 + 0x02, 0x8b, 0x8a, 0x43, 0x1b, 0x21, 0x09, 0x02, 0x51, 0x18, 0x01, 0x83, 0xe8, 0x48, 0x40, 0x7b, /// 0x2a70 + 0x00, 0x07, 0x04, 0xd4, 0xe7, 0x48, 0x01, 0x78, 0x04, 0x22, 0x11, 0x43, 0x01, 0x70, 0xe0, 0x49, /// 0x2a80 + 0x0a, 0x20, 0xc0, 0x31, 0x08, 0x75, 0xe2, 0x48, 0x10, 0x22, 0x40, 0x30, 0x01, 0x78, 0x11, 0x43, /// 0x2a90 + 0x01, 0x70, 0x80, 0x38, 0x81, 0x8e, 0x40, 0x22, 0x11, 0x43, 0x81, 0x86, 0x10, 0x46, 0xfd, 0xf7, /// 0x2aa0 + 0x78, 0xfe, 0x10, 0xbd, 0xf0, 0xb5, 0xd6, 0x48, 0x8b, 0xb0, 0x40, 0x7b, 0x80, 0x07, 0x03, 0xd0, /// 0x2ab0 + 0xff, 0xf7, 0xb7, 0xff, 0x0b, 0xb0, 0xf0, 0xbd, 0xd5, 0x4f, 0xd1, 0x49, 0x80, 0x37, 0x38, 0x79, /// 0x2ac0 + 0xc0, 0x39, 0x3c, 0x46, 0x82, 0x07, 0x40, 0x3c, 0x06, 0x91, 0x00, 0x2a, 0x1a, 0xda, 0x09, 0x68, /// 0x2ad0 + 0xa2, 0x6c, 0x89, 0x1a, 0xff, 0x22, 0x2d, 0x32, 0x91, 0x42, 0x13, 0xd9, 0x79, 0x79, 0x03, 0x29, /// 0x2ae0 + 0x01, 0xd2, 0x04, 0x21, 0x0c, 0xe0, 0xca, 0x49, 0x01, 0x20, 0x40, 0x39, 0x8a, 0x8e, 0x00, 0x03, /// 0x2af0 + 0x02, 0x43, 0x8a, 0x86, 0xfd, 0xf7, 0x4d, 0xfe, 0x38, 0x79, 0xfd, 0x21, 0x08, 0x40, 0x01, 0x21, /// 0x2b00 + 0x08, 0x43, 0x38, 0x71, 0x60, 0x78, 0x41, 0x06, 0x13, 0xd5, 0x06, 0x99, 0xa2, 0x6c, 0x09, 0x68, /// 0x2b10 + 0x89, 0x1a, 0xff, 0x22, 0xf5, 0x32, 0x91, 0x42, 0x0b, 0xd9, 0xbf, 0x21, 0x08, 0x40, 0xbc, 0x49, /// 0x2b20 + 0x60, 0x70, 0x40, 0x39, 0x8a, 0x8e, 0xff, 0x20, 0x01, 0x30, 0x02, 0x43, 0x8a, 0x86, 0xfd, 0xf7, /// 0x2b30 + 0x30, 0xfe, 0x20, 0x7e, 0x00, 0x28, 0x02, 0xd0, 0xff, 0xf7, 0x30, 0xfe, 0xba, 0xe7, 0x06, 0x98, /// 0x2b40 + 0xaf, 0x4d, 0x00, 0x68, 0x40, 0x3d, 0x00, 0x90, 0xe9, 0x6d, 0x0a, 0x22, 0x41, 0x1a, 0x28, 0x46, /// 0x2b50 + 0x80, 0x30, 0x08, 0x90, 0x82, 0x5e, 0x00, 0x98, 0x91, 0x42, 0x03, 0xdb, 0xe8, 0x65, 0x48, 0x20, /// 0x2b60 + 0x20, 0x76, 0xe9, 0xe7, 0xa9, 0x6d, 0xa6, 0x4e, 0x41, 0x1a, 0xa9, 0x48, 0x6a, 0x6e, 0x20, 0x38, /// 0x2b70 + 0x60, 0x36, 0x05, 0x90, 0x91, 0x42, 0x7d, 0xdb, 0x00, 0x98, 0xa8, 0x65, 0x60, 0x78, 0x01, 0x07, /// 0x2b80 + 0x0b, 0xd5, 0xf7, 0x21, 0x08, 0x40, 0x32, 0x21, 0x69, 0x66, 0x10, 0x21, 0x08, 0x43, 0x60, 0x70, /// 0x2b90 + 0x00, 0x20, 0xb8, 0x81, 0xff, 0xf7, 0xe8, 0xfd, 0x8c, 0xe7, 0x39, 0x79, 0x0a, 0x07, 0x0f, 0xd5, /// 0x2ba0 + 0xa2, 0x78, 0x93, 0x06, 0x0c, 0xd5, 0xdf, 0x21, 0x0a, 0x40, 0xa2, 0x70, 0x32, 0x21, 0x69, 0x66, /// 0x2bb0 + 0x40, 0x21, 0x08, 0x43, 0x60, 0x70, 0x00, 0x98, 0xa0, 0x64, 0xff, 0xf7, 0xb0, 0xfd, 0x79, 0xe7, /// 0x2bc0 + 0x82, 0x06, 0x08, 0xd5, 0xdf, 0x21, 0x08, 0x40, 0x60, 0x70, 0x32, 0x20, 0x68, 0x66, 0xff, 0x20, /// 0x2bd0 + 0xfe, 0xf7, 0x22, 0xfc, 0x6e, 0xe7, 0x48, 0x07, 0x0d, 0xd5, 0xfb, 0x20, 0x01, 0x40, 0x39, 0x71, /// 0x2be0 + 0x32, 0x20, 0x68, 0x66, 0xff, 0xf7, 0x71, 0xfd, 0x06, 0x98, 0x00, 0x68, 0xa0, 0x64, 0x78, 0x79, /// 0x2bf0 + 0x40, 0x1c, 0x78, 0x71, 0x5e, 0xe7, 0x08, 0x07, 0x23, 0xd5, 0xa7, 0x78, 0xf8, 0x07, 0x20, 0xd0, /// 0x2c00 + 0x83, 0x48, 0x09, 0x90, 0x00, 0x8f, 0x64, 0x21, 0xfe, 0xf7, 0x30, 0xfc, 0x05, 0x99, 0x89, 0x7f, /// 0x2c10 + 0x08, 0x1a, 0x79, 0x08, 0x49, 0x00, 0x23, 0x30, 0xa1, 0x70, 0x00, 0x28, 0x00, 0xdc, 0x40, 0x42, /// 0x2c20 + 0x14, 0x28, 0x2d, 0xdb, 0x32, 0x20, 0x68, 0x66, 0x09, 0x98, 0x02, 0x88, 0x74, 0x48, 0xc0, 0x30, /// 0x2c30 + 0xc2, 0x80, 0x02, 0x22, 0x11, 0x43, 0xa1, 0x70, 0x00, 0x99, 0x81, 0x60, 0xff, 0xf7, 0x2e, 0xfd, /// 0x2c40 + 0x38, 0xe7, 0x73, 0x48, 0x40, 0x38, 0x00, 0x8d, 0x00, 0x28, 0x0a, 0xd0, 0x70, 0x7f, 0x07, 0x28, /// 0x2c50 + 0x07, 0xd2, 0xb0, 0x7f, 0x0a, 0x28, 0x18, 0xd2, 0xff, 0xf7, 0x81, 0xfb, 0xc0, 0x1d, 0x0e, 0x28, /// 0x2c60 + 0x0e, 0xd9, 0x00, 0x20, 0x70, 0x77, 0x30, 0x7f, 0x00, 0x28, 0x01, 0xd0, 0x40, 0x1e, 0x30, 0x77, /// 0x2c70 + 0x06, 0x98, 0x00, 0xe0, 0x04, 0xe0, 0x00, 0x68, 0xa8, 0x65, 0xff, 0xf7, 0xe5, 0xfb, 0x19, 0xe7, /// 0x2c80 + 0x63, 0x48, 0x40, 0x38, 0x00, 0x8d, 0x00, 0x28, 0x86, 0xd0, 0x70, 0x7f, 0x60, 0x49, 0x40, 0x1c, /// 0x2c90 + 0x70, 0x77, 0x40, 0x39, 0x08, 0x8d, 0x80, 0x22, 0x83, 0x06, 0x00, 0x2b, 0x39, 0xd0, 0xc3, 0x07, /// 0x2ca0 + 0x04, 0xd0, 0x01, 0x20, 0x48, 0x85, 0xf0, 0x77, 0x03, 0x20, 0x4a, 0xe0, 0x83, 0x07, 0x05, 0xd5, /// 0x2cb0 + 0x02, 0x20, 0x48, 0x85, 0x01, 0x20, 0xf0, 0x77, 0x05, 0x20, 0x42, 0xe0, 0x43, 0x07, 0x04, 0xd5, /// 0x2cc0 + 0x04, 0x22, 0x90, 0x43, 0x08, 0x85, 0x02, 0x20, 0x3b, 0xe0, 0x03, 0x07, 0x04, 0xd5, 0x08, 0x22, /// 0x2cd0 + 0x90, 0x43, 0x08, 0x85, 0x01, 0x20, 0x34, 0xe0, 0xc3, 0x06, 0x0e, 0xd5, 0x05, 0x9a, 0x92, 0x79, /// 0x2ce0 + 0x52, 0x06, 0x04, 0xd5, 0x10, 0x20, 0x48, 0x85, 0x01, 0x20, 0xf0, 0x77, 0x02, 0xe0, 0x10, 0x22, /// 0x2cf0 + 0x90, 0x43, 0x08, 0x85, 0xff, 0xf7, 0x1f, 0xfb, 0xdc, 0xe6, 0x83, 0x06, 0x09, 0xd5, 0x20, 0x20, /// 0x2d00 + 0x48, 0x85, 0x01, 0x20, 0xf0, 0x77, 0x05, 0x98, 0x00, 0x7b, 0x40, 0x1e, 0x10, 0x43, 0xc0, 0xb2, /// 0x2d10 + 0x17, 0xe0, 0xc0, 0x22, 0x02, 0x40, 0x20, 0xd0, 0xc0, 0x2a, 0x06, 0xd1, 0x05, 0x9a, 0xd2, 0x79, /// 0x2d20 + 0x52, 0x07, 0x01, 0xd5, 0x40, 0x22, 0x00, 0xe0, 0x80, 0x22, 0x52, 0x06, 0x0c, 0xd5, 0x40, 0x22, /// 0x2d30 + 0x90, 0x43, 0x08, 0x85, 0x05, 0x98, 0xfb, 0x21, 0xc0, 0x79, 0x08, 0x40, 0x05, 0x99, 0xc8, 0x71, /// 0x2d40 + 0x06, 0x20, 0xff, 0xf7, 0xec, 0xfa, 0xb5, 0xe6, 0x05, 0x98, 0x04, 0x21, 0xc0, 0x79, 0x08, 0x43, /// 0x2d50 + 0x05, 0x99, 0xc8, 0x71, 0xff, 0xf7, 0xcd, 0xfa, 0xac, 0xe6, 0xc2, 0x05, 0x06, 0xd5, 0xff, 0x22, /// 0x2d60 + 0x01, 0x32, 0x90, 0x43, 0x08, 0x85, 0xff, 0xf7, 0xb5, 0xfa, 0xa3, 0xe6, 0x82, 0x05, 0x86, 0xd5, /// 0x2d70 + 0x06, 0x9a, 0xab, 0x6d, 0x12, 0x68, 0xd3, 0x1a, 0x64, 0x2b, 0xbd, 0xda, 0xeb, 0x6d, 0x0a, 0x24, /// 0x2d80 + 0x9b, 0x1a, 0x08, 0x9a, 0x14, 0x5f, 0x1a, 0x19, 0xff, 0x23, 0x5f, 0x33, 0x9a, 0x42, 0xb3, 0xdd, /// 0x2d90 + 0x01, 0x22, 0x52, 0x02, 0x90, 0x43, 0x08, 0x85, 0x19, 0x48, 0x06, 0x21, 0x80, 0x38, 0x81, 0x72, /// 0x2da0 + 0xff, 0xf7, 0x8c, 0xfa, 0x86, 0xe6, 0x16, 0x48, 0x10, 0xb5, 0x1b, 0x49, 0x40, 0x38, 0xc1, 0x62, /// 0x2db0 + 0x17, 0x48, 0x40, 0x30, 0xc1, 0x78, 0x12, 0x48, 0x20, 0x38, 0xc1, 0x73, 0x10, 0x49, 0x01, 0x20, /// 0x2dc0 + 0x60, 0x31, 0xc8, 0x77, 0x02, 0x20, 0xfd, 0xf7, 0x8c, 0xfe, 0x10, 0xbd, 0xf0, 0xb5, 0x09, 0x22, /// 0x2dd0 + 0x12, 0x49, 0x92, 0x01, 0x0a, 0x4c, 0x8a, 0x18, 0x15, 0x78, 0x20, 0x7c, 0x13, 0x22, 0x52, 0x01, /// 0x2de0 + 0xc3, 0x07, 0x8a, 0x18, 0x87, 0xb0, 0x00, 0x2b, 0x25, 0xd0, 0x00, 0x2d, 0x23, 0xd1, 0xd1, 0x79, /// 0x2df0 + 0x49, 0x1c, 0x15, 0xe0, 0xd0, 0x4d, 0x00, 0x00, 0x88, 0x13, 0x00, 0x00, 0x0c, 0x04, 0x00, 0x00, /// 0x2e00 + 0xf0, 0x02, 0x00, 0x20, 0x00, 0x30, 0x00, 0x40, 0x00, 0x1f, 0x00, 0x00, 0x00, 0x34, 0x00, 0x40, /// 0x2e10 + 0x40, 0x00, 0x00, 0x20, 0x40, 0x6c, 0x00, 0x40, 0x0c, 0x22, 0x00, 0x00, 0x30, 0x01, 0x00, 0x20, /// 0x2e20 + 0xc9, 0xb2, 0xd1, 0x71, 0x03, 0x29, 0x02, 0xd2, 0x40, 0x1e, 0x20, 0x74, 0x03, 0xe0, 0x40, 0x1c, /// 0x2e30 + 0x20, 0x74, 0x00, 0x20, 0xd0, 0x71, 0xbd, 0x4e, 0x27, 0x7c, 0x30, 0x7d, 0x05, 0x90, 0x70, 0x7d, /// 0x2e40 + 0x01, 0x90, 0xbb, 0x48, 0x01, 0x46, 0xa0, 0x31, 0x80, 0x30, 0x00, 0x91, 0xc1, 0x7b, 0x04, 0x91, /// 0x2e50 + 0x81, 0x7b, 0x02, 0x91, 0x41, 0x7b, 0x03, 0x7b, 0x03, 0x93, 0x3b, 0x00, 0xfe, 0xf7, 0x30, 0xfb, /// 0x2e60 + 0x11, 0x0a, 0x0d, 0x13, 0x15, 0x1f, 0x23, 0x36, 0x3e, 0x43, 0x4a, 0x60, 0x68, 0x6d, 0x78, 0x7d, /// 0x2e70 + 0x82, 0xa8, 0xaa, 0x00, 0xff, 0xf7, 0x97, 0xff, 0x9c, 0xe0, 0xa8, 0x07, 0x00, 0xd5, 0xfe, 0xe7, /// 0x2e80 + 0x00, 0x20, 0xd0, 0x71, 0x96, 0xe0, 0x30, 0x20, 0x0a, 0xe0, 0x05, 0x99, 0x30, 0x29, 0xf7, 0xd1, /// 0x2e90 + 0x00, 0x99, 0x01, 0x9b, 0x4b, 0x72, 0xf1, 0x8a, 0x49, 0xba, 0x41, 0x84, 0xf0, 0xe7, 0x31, 0x20, /// 0x2ea0 + 0xff, 0xf7, 0x93, 0xf9, 0x86, 0xe0, 0x05, 0x9b, 0x31, 0x2b, 0xe9, 0xd1, 0x01, 0x9d, 0x05, 0x71, /// 0x2eb0 + 0xb3, 0x7d, 0x43, 0x71, 0xf6, 0x7d, 0x86, 0x71, 0x8d, 0x42, 0x02, 0xd2, 0x8b, 0x42, 0x00, 0xd2, /// 0x2ec0 + 0x43, 0x73, 0x02, 0x99, 0x8b, 0x42, 0xdb, 0xd2, 0x83, 0x73, 0xd9, 0xe7, 0x00, 0x7a, 0x03, 0x99, /// 0x2ed0 + 0x81, 0x42, 0x01, 0xd0, 0x02, 0x20, 0x35, 0xe0, 0x07, 0x20, 0x37, 0xe0, 0xe8, 0x07, 0xcf, 0xd0, /// 0x2ee0 + 0x03, 0x98, 0x10, 0x72, 0xcc, 0xe7, 0x40, 0x7a, 0x81, 0x42, 0x01, 0xd0, 0x01, 0x20, 0x29, 0xe0, /// 0x2ef0 + 0x09, 0x20, 0x2b, 0xe0, 0x8e, 0x4b, 0xed, 0x07, 0x80, 0x33, 0x1b, 0x79, 0x00, 0x2d, 0x09, 0xd0, /// 0x2f00 + 0x51, 0x72, 0x8b, 0x42, 0x00, 0xd2, 0x01, 0x71, 0x41, 0x8c, 0x27, 0x29, 0xb8, 0xd1, 0x04, 0x21, /// 0x2f10 + 0x01, 0x71, 0xb5, 0xe7, 0x99, 0x42, 0xb3, 0xd9, 0x43, 0x73, 0x08, 0x20, 0x20, 0x74, 0xaf, 0xe7, /// 0x2f20 + 0x80, 0x7a, 0x02, 0x99, 0x81, 0x42, 0x01, 0xd0, 0x04, 0x20, 0x0b, 0xe0, 0x0b, 0x20, 0x0d, 0xe0, /// 0x2f30 + 0xe8, 0x07, 0xa5, 0xd0, 0x02, 0x98, 0x90, 0x72, 0xa2, 0xe7, 0xc0, 0x7a, 0x04, 0x99, 0x81, 0x42, /// 0x2f40 + 0x03, 0xd0, 0x03, 0x20, 0xff, 0xf7, 0x31, 0xf9, 0x34, 0xe0, 0x0d, 0x20, 0x20, 0x74, 0x31, 0xe0, /// 0x2f50 + 0xe8, 0x07, 0x95, 0xd0, 0x04, 0x98, 0xd0, 0x72, 0x92, 0xe7, 0xff, 0xf7, 0x14, 0xf9, 0xc1, 0xb2, /// 0x2f60 + 0x00, 0x20, 0xef, 0xe7, 0xe9, 0x07, 0x1c, 0xd0, 0xb1, 0x6e, 0x81, 0x60, 0xff, 0x20, 0xc3, 0x30, /// 0x2f70 + 0x70, 0x81, 0x70, 0x48, 0x01, 0x68, 0x80, 0x30, 0x0a, 0x46, 0xff, 0x3a, 0x2d, 0x3a, 0xc2, 0x65, /// 0x2f80 + 0x01, 0x66, 0x42, 0x6e, 0x89, 0x1a, 0x81, 0x65, 0x6a, 0x49, 0x05, 0x20, 0x40, 0x31, 0x88, 0x72, /// 0x2f90 + 0x00, 0x98, 0x0f, 0x21, 0x01, 0x72, 0x68, 0x48, 0x01, 0x78, 0x04, 0x22, 0x11, 0x43, 0x01, 0x70, /// 0x2fa0 + 0x08, 0xe0, 0xa9, 0x07, 0x06, 0xd5, 0x80, 0x68, 0xb0, 0x66, 0x00, 0x20, 0xd0, 0x71, 0x03, 0xe0, /// 0x2fb0 + 0xfe, 0xf7, 0x6b, 0xfb, 0x20, 0x7c, 0x40, 0x1c, 0x20, 0x74, 0x07, 0xb0, 0xf0, 0xbd, 0xf8, 0xb5, /// 0x2fc0 + 0x5b, 0x4c, 0x80, 0x34, 0xa2, 0x78, 0x90, 0x07, 0x60, 0xd5, 0x58, 0x4d, 0x20, 0x46, 0x40, 0x38, /// 0x2fd0 + 0x80, 0x35, 0x01, 0x88, 0xeb, 0x88, 0xc9, 0x1a, 0x00, 0x29, 0x00, 0xdc, 0x49, 0x42, 0x54, 0x4b, /// 0x2fe0 + 0x53, 0x4f, 0xc0, 0x33, 0xdb, 0x89, 0xbe, 0x8e, 0x99, 0x42, 0x31, 0xdd, 0xfd, 0x21, 0x0a, 0x40, /// 0x2ff0 + 0xa2, 0x70, 0x00, 0x8f, 0x64, 0x21, 0x00, 0x90, 0xfe, 0xf7, 0x38, 0xfa, 0x3d, 0x46, 0x20, 0x35, /// 0x3000 + 0x23, 0x38, 0x29, 0x46, 0xa8, 0x77, 0x40, 0x31, 0xc8, 0x70, 0xaf, 0x21, 0x00, 0x98, 0x09, 0x01, /// 0x3010 + 0x40, 0x1a, 0x19, 0x21, 0xfe, 0xf7, 0x40, 0xfa, 0x48, 0x49, 0x08, 0x82, 0x08, 0x20, 0x06, 0x43, /// 0x3020 + 0xbe, 0x86, 0xfd, 0xf7, 0xb6, 0xfb, 0xa9, 0x7f, 0x28, 0x46, 0x80, 0x30, 0x73, 0x29, 0x02, 0xd1, /// 0x3030 + 0xe9, 0x7f, 0x00, 0x29, 0x06, 0xd0, 0x21, 0x78, 0x49, 0x06, 0x49, 0x0e, 0x21, 0x70, 0x48, 0x21, /// 0x3040 + 0xc1, 0x72, 0x23, 0xe0, 0x21, 0x78, 0x80, 0x22, 0x11, 0x43, 0x21, 0x70, 0x30, 0x21, 0xf7, 0xe7, /// 0x3050 + 0x38, 0x49, 0x3b, 0x4b, 0x0a, 0x68, 0xa9, 0x68, 0x51, 0x1a, 0x99, 0x42, 0x16, 0xdd, 0x69, 0x79, /// 0x3060 + 0x02, 0x29, 0x07, 0xd2, 0xc3, 0x89, 0x80, 0x24, 0x23, 0x43, 0xc3, 0x81, 0x49, 0x1c, 0xaa, 0x60, /// 0x3070 + 0x69, 0x71, 0x0b, 0xe0, 0x01, 0x20, 0xc0, 0x03, 0x06, 0x43, 0xbe, 0x86, 0xfd, 0xf7, 0x89, 0xfb, /// 0x3080 + 0xa0, 0x78, 0xfd, 0x21, 0x08, 0x40, 0xa0, 0x70, 0x00, 0x20, 0x68, 0x71, 0x00, 0x20, 0xf8, 0xbd, /// 0x3090 + 0x70, 0xb5, 0x27, 0x49, 0x9f, 0x23, 0x80, 0x31, 0x4a, 0x78, 0x1a, 0x40, 0x4a, 0x70, 0x0b, 0x46, /// 0x30a0 + 0x20, 0x33, 0x1c, 0x7c, 0x05, 0x78, 0x80, 0x39, 0x8a, 0x8e, 0xac, 0x42, 0x0e, 0xd1, 0x5c, 0x7c, /// 0x30b0 + 0x45, 0x78, 0xac, 0x42, 0x0a, 0xd1, 0x9c, 0x7c, 0x85, 0x78, 0xac, 0x42, 0x06, 0xd1, 0xdb, 0x7c, /// 0x30c0 + 0xc0, 0x78, 0x83, 0x42, 0x02, 0xd1, 0x01, 0x20, 0x40, 0x02, 0x01, 0xe0, 0xff, 0x20, 0x01, 0x30, /// 0x30d0 + 0x02, 0x43, 0x8a, 0x86, 0xfd, 0xf7, 0x5d, 0xfb, 0x70, 0xbd, 0x70, 0xb5, 0x14, 0x48, 0xdf, 0x22, /// 0x30e0 + 0x80, 0x30, 0x41, 0x78, 0x04, 0x46, 0x11, 0x40, 0x41, 0x70, 0x40, 0x3c, 0x60, 0x7e, 0x3b, 0x28, /// 0x30f0 + 0x15, 0xd1, 0x23, 0x46, 0x80, 0x33, 0x18, 0x79, 0xfd, 0x21, 0x08, 0x40, 0x01, 0x21, 0x08, 0x43, /// 0x3100 + 0x18, 0x71, 0x0b, 0x49, 0xa5, 0x7e, 0x8a, 0x8e, 0x02, 0x2d, 0x02, 0xd1, 0xe4, 0x7e, 0xbb, 0x2c, /// 0x3110 + 0x06, 0xd0, 0x01, 0x20, 0x00, 0x03, 0x02, 0x43, 0x8a, 0x86, 0xfd, 0xf7, 0x3a, 0xfb, 0x70, 0xbd, /// 0x3120 + 0x08, 0x24, 0x20, 0x43, 0x18, 0x71, 0xa0, 0x02, 0xf5, 0xe7, 0x00, 0x00, 0x30, 0x03, 0x00, 0x20, /// 0x3130 + 0x00, 0x00, 0x00, 0x20, 0x30, 0x02, 0x00, 0x20, 0x40, 0x6c, 0x00, 0x40, 0x00, 0x30, 0x00, 0x40, /// 0x3140 + 0xdc, 0x05, 0x00, 0x00, 0x94, 0x28, 0x94, 0x1f, 0x94, 0x15, 0x94, 0x15, 0x94, 0x0f, 0x94, 0x14, /// 0x3150 + 0x14, 0x14, 0x00, 0x00, 0x93, 0x3e, 0x85, 0x4d, 0x89, 0x43, 0x86, 0x55, 0x86, 0x5c, 0x86, 0x60, /// 0x3160 + 0x14, 0x00, 0x01, 0x50, 0x01, 0x00, 0x01, 0x00, 0x4e, 0x6f, 0x76, 0x20, 0x32, 0x31, 0x20, 0x32, /// 0x3170 + 0x30, 0x31, 0x38, 0x00, 0x31, 0x34, 0x3a, 0x33, 0x39, 0x3a, 0x35, 0x36, +}; + +unsigned char idt_firmware_sram[] = { + 0x0c, 0x0b, 0x00, 0x20, 0x30, 0x11, 0x00, 0x20, 0x08, 0x1d, 0x00, 0x00, 0xac, 0x29, 0x00, 0x00, /// 0x4010 + 0x09, 0x09, 0x00, 0x20, 0x97, 0x1a, 0x00, 0x00, 0xa3, 0x1e, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, /// 0x4020 + 0x20, 0x92, 0x02, 0x00, 0x87, 0x01, 0x01, 0x02, 0xf3, 0x04, 0x1e, 0x12, 0xd4, 0x01, 0x09, 0x00, /// 0x4030 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x13, 0x78, 0x05, 0x02, 0x80, 0x00, 0x00, 0x00, 0x00, /// 0x4040 + 0x23, 0x01, 0x9a, 0x02, 0x90, 0x01, 0xe8, 0x03, 0x4c, 0x1d, 0x08, 0xff, 0x00, 0x00, 0x00, 0x00, /// 0x4050 + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /// 0x4060 + 0x70, 0xb5, 0x72, 0xb6, 0x23, 0x48, 0x22, 0x49, 0x41, 0x60, 0x23, 0x49, 0x23, 0x4c, 0x81, 0x67, /// 0x4070 + 0x23, 0x4d, 0x62, 0xb6, 0x60, 0x68, 0x21, 0x46, 0xe8, 0x61, 0x10, 0x22, 0x08, 0x31, 0x21, 0x48, /// 0x4080 + 0x00, 0xf0, 0xea, 0xf9, 0x20, 0x49, 0x08, 0x78, 0x00, 0x28, 0x00, 0xd1, 0x1f, 0x49, 0x1c, 0x48, /// 0x4090 + 0x10, 0x22, 0x68, 0x30, 0x00, 0xf0, 0xe6, 0xf9, 0xa0, 0x78, 0xe8, 0x70, 0x58, 0x20, 0x28, 0x87, /// 0x40a0 + 0x20, 0x8b, 0x64, 0x21, 0x00, 0xf0, 0xe4, 0xf9, 0x15, 0x49, 0x40, 0x1e, 0x40, 0x31, 0x88, 0x72, /// 0x40b0 + 0x13, 0x48, 0xa1, 0x7e, 0x60, 0x30, 0x81, 0x70, 0x15, 0x49, 0x20, 0x20, 0x08, 0x81, 0x60, 0x22, /// 0x40c0 + 0x8a, 0x83, 0x13, 0x49, 0x20, 0x31, 0x8a, 0x89, 0x02, 0x43, 0x8a, 0x81, 0xe0, 0x8a, 0x64, 0x21, /// 0x40d0 + 0x00, 0xf0, 0xce, 0xf9, 0x0a, 0x49, 0x21, 0x38, 0x20, 0x31, 0x88, 0x77, 0xe0, 0x8a, 0xaf, 0x21, /// 0x40e0 + 0x09, 0x01, 0x40, 0x1a, 0x19, 0x21, 0x00, 0xf0, 0xc9, 0xf9, 0x0a, 0x49, 0x08, 0x82, 0x70, 0xbd, /// 0x40f0 + 0x09, 0x09, 0x00, 0x20, 0x00, 0x01, 0x00, 0x20, 0x0d, 0x0b, 0x00, 0x20, 0x20, 0x06, 0x00, 0x20, /// 0x4100 + 0x00, 0x00, 0x00, 0x20, 0xb0, 0x00, 0x00, 0x20, 0x60, 0x3e, 0x00, 0x00, 0x20, 0x11, 0x00, 0x20, /// 0x4110 + 0x00, 0x6c, 0x00, 0x40, 0x00, 0x30, 0x00, 0x40, 0x10, 0xb5, 0xc1, 0x48, 0x0c, 0x21, 0x01, 0x73, /// 0x4120 + 0x38, 0x21, 0x41, 0x73, 0x0a, 0x21, 0x81, 0x73, 0xbe, 0x49, 0x09, 0x8f, 0xc1, 0x73, 0x09, 0x0a, /// 0x4130 + 0x01, 0x74, 0x03, 0x20, 0x00, 0xf0, 0xa8, 0xf9, 0x10, 0xbd, 0xf8, 0xb5, 0xb8, 0x49, 0x20, 0x31, /// 0x4140 + 0x48, 0x7b, 0xc2, 0x06, 0x0e, 0xd5, 0xef, 0x22, 0x10, 0x40, 0x48, 0x73, 0xb5, 0x48, 0x80, 0x22, /// 0x4150 + 0x40, 0x38, 0x81, 0x8e, 0x11, 0x43, 0x81, 0x86, 0xb3, 0x48, 0x81, 0x89, 0x04, 0x22, 0x11, 0x43, /// 0x4160 + 0x81, 0x81, 0xf8, 0xbd, 0x43, 0x07, 0xfb, 0x22, 0x00, 0x2b, 0x0b, 0xda, 0x10, 0x40, 0x10, 0x22, /// 0x4170 + 0x10, 0x43, 0x48, 0x73, 0xad, 0x48, 0x01, 0x21, 0x81, 0x80, 0x01, 0x88, 0x30, 0x22, 0x91, 0x43, /// 0x4180 + 0x01, 0x80, 0xf8, 0xbd, 0xaa, 0x48, 0x01, 0x7e, 0x00, 0x29, 0x02, 0xd0, 0x00, 0xf0, 0x52, 0xfb, /// 0x4190 + 0xf8, 0xbd, 0xa3, 0x49, 0xa2, 0x4c, 0x80, 0x39, 0x0d, 0x68, 0xe1, 0x6b, 0xa5, 0x4b, 0x69, 0x1a, /// 0x41a0 + 0x99, 0x42, 0x03, 0xdb, 0x48, 0x21, 0xe5, 0x63, 0x01, 0x76, 0xef, 0xe7, 0xa0, 0x6b, 0x21, 0x6c, /// 0x41b0 + 0x28, 0x1a, 0x88, 0x42, 0xec, 0xdb, 0x9e, 0x48, 0xa5, 0x63, 0x20, 0x38, 0x41, 0x78, 0x4b, 0x07, /// 0x41c0 + 0x06, 0xd5, 0x11, 0x40, 0x41, 0x70, 0x32, 0x20, 0x20, 0x64, 0x00, 0xf0, 0x63, 0xf9, 0xf8, 0xbd, /// 0x41d0 + 0x0a, 0x07, 0x07, 0xd5, 0xf7, 0x22, 0x11, 0x40, 0x41, 0x70, 0x32, 0x20, 0x20, 0x64, 0x00, 0xf0, /// 0x41e0 + 0x5f, 0xf9, 0xf8, 0xbd, 0x86, 0x78, 0x31, 0x07, 0x89, 0x0f, 0x02, 0xd0, 0x00, 0xf0, 0xcf, 0xfa, /// 0x41f0 + 0xf8, 0xbd, 0x8b, 0x4f, 0xf0, 0x07, 0x80, 0x37, 0x00, 0x28, 0x22, 0xd0, 0x89, 0x48, 0x00, 0x90, /// 0x4200 + 0x00, 0x8f, 0x64, 0x21, 0x00, 0xf0, 0x34, 0xf9, 0x86, 0x49, 0x72, 0x08, 0x20, 0x39, 0x89, 0x7f, /// 0x4210 + 0x52, 0x00, 0x08, 0x1a, 0x86, 0x49, 0x23, 0x30, 0x20, 0x39, 0x8a, 0x70, 0x00, 0x28, 0x00, 0xdc, /// 0x4220 + 0x40, 0x42, 0x14, 0x28, 0xe4, 0xdb, 0x32, 0x20, 0x20, 0x64, 0x00, 0x98, 0x03, 0x88, 0x7c, 0x48, /// 0x4230 + 0xc0, 0x30, 0x83, 0x80, 0x02, 0x20, 0x02, 0x43, 0x8a, 0x70, 0x3d, 0x64, 0xff, 0xf7, 0x6c, 0xff, /// 0x4240 + 0xf8, 0xbd, 0x00, 0xf0, 0xba, 0xf9, 0x78, 0x7f, 0x00, 0x28, 0xf9, 0xd0, 0x40, 0x1e, 0x78, 0x77, /// 0x4250 + 0xf8, 0xbd, 0x10, 0xb5, 0x75, 0x48, 0x00, 0x21, 0x80, 0x88, 0x00, 0x07, 0x00, 0xd5, 0x02, 0x21, /// 0x4260 + 0x75, 0x48, 0x80, 0x8b, 0xc0, 0x04, 0x01, 0xd5, 0x01, 0x20, 0x01, 0x43, 0x73, 0x48, 0x80, 0x89, /// 0x4270 + 0xc0, 0x06, 0x01, 0xd5, 0x04, 0x20, 0x01, 0x43, 0x6a, 0x4b, 0x40, 0x3b, 0x9a, 0x8e, 0x50, 0x07, /// 0x4280 + 0x40, 0x0f, 0x48, 0x40, 0x05, 0xd0, 0xd2, 0x08, 0xd2, 0x00, 0x0a, 0x43, 0x9a, 0x86, 0x00, 0xf0, /// 0x4290 + 0x0d, 0xf9, 0x10, 0xbd, 0x70, 0xb5, 0x66, 0x4a, 0x20, 0x3a, 0x93, 0x78, 0x98, 0x07, 0x31, 0xd5, /// 0x42a0 + 0x5f, 0x4c, 0x60, 0x49, 0xc0, 0x34, 0x08, 0x88, 0xa5, 0x88, 0x40, 0x1b, 0x00, 0x28, 0x00, 0xdc, /// 0x42b0 + 0x40, 0x42, 0x63, 0x4d, 0xa8, 0x42, 0x16, 0xdd, 0xfd, 0x20, 0x03, 0x40, 0x93, 0x70, 0x0d, 0x8f, /// 0x42c0 + 0x64, 0x21, 0x28, 0x46, 0x00, 0xf0, 0xd4, 0xf8, 0x56, 0x49, 0x23, 0x38, 0x20, 0x39, 0x88, 0x77, /// 0x42d0 + 0xaf, 0x20, 0x00, 0x01, 0x28, 0x1a, 0x19, 0x21, 0x00, 0xf0, 0xd0, 0xf8, 0x56, 0x49, 0x08, 0x82, /// 0x42e0 + 0x00, 0x20, 0xa0, 0x71, 0x0e, 0xe0, 0x4e, 0x48, 0x52, 0x4c, 0x80, 0x38, 0x02, 0x68, 0xff, 0x30, /// 0x42f0 + 0x01, 0x30, 0x03, 0x6c, 0xd3, 0x1a, 0xa3, 0x42, 0x04, 0xdd, 0x8b, 0x7b, 0x80, 0x24, 0x23, 0x43, /// 0x4300 + 0x8b, 0x73, 0x02, 0x64, 0x00, 0x20, 0x70, 0xbd, 0xf8, 0xb5, 0x45, 0x48, 0x4d, 0x49, 0x80, 0x38, /// 0x4310 + 0x80, 0x6f, 0x00, 0x26, 0x88, 0x42, 0x14, 0xd1, 0x41, 0x4a, 0xa0, 0x32, 0x50, 0x79, 0x00, 0x28, /// 0x4320 + 0x14, 0xd0, 0x40, 0x49, 0x20, 0x39, 0x88, 0x79, 0x43, 0x1c, 0x8b, 0x71, 0x0a, 0x28, 0x08, 0xd9, /// 0x4330 + 0x45, 0x48, 0x01, 0x23, 0x03, 0x80, 0x03, 0x23, 0x03, 0x80, 0x41, 0x23, 0x03, 0x83, 0x56, 0x71, /// 0x4340 + 0x8e, 0x71, 0x38, 0x4f, 0xb8, 0x7b, 0x00, 0x28, 0x07, 0xd1, 0x03, 0xe0, 0x3f, 0x48, 0x00, 0xf0, /// 0x4350 + 0xb3, 0xf8, 0xf6, 0xe7, 0x38, 0x7b, 0x00, 0x28, 0x02, 0xd0, 0x3d, 0x48, 0x00, 0xf0, 0xb2, 0xf8, /// 0x4360 + 0x30, 0x48, 0x40, 0x38, 0x80, 0x8e, 0x00, 0x06, 0x01, 0xd5, 0xff, 0xf7, 0x93, 0xff, 0xff, 0xf7, /// 0x4370 + 0x70, 0xff, 0x2b, 0x4d, 0x20, 0x35, 0x28, 0x7a, 0x00, 0x28, 0x4e, 0xd1, 0xe8, 0x7a, 0x2c, 0x46, /// 0x4380 + 0x60, 0x3c, 0x00, 0x28, 0x11, 0xd0, 0x40, 0x1e, 0xe8, 0x72, 0xa0, 0x7a, 0x05, 0x28, 0x44, 0xd1, /// 0x4390 + 0x30, 0x48, 0x00, 0xf0, 0x97, 0xf8, 0x28, 0x7b, 0xe9, 0x7a, 0x40, 0x1e, 0x81, 0x42, 0x3c, 0xd1, /// 0x43a0 + 0x20, 0x46, 0x80, 0x30, 0x06, 0x86, 0x86, 0x85, 0x37, 0xe0, 0xa0, 0x7a, 0x1c, 0x4e, 0x03, 0x00, /// 0x43b0 + 0x00, 0xf0, 0x8e, 0xf8, 0x07, 0x05, 0x16, 0x1a, 0x1e, 0x22, 0x2e, 0x31, 0x33, 0x00, 0x18, 0x48, /// 0x43c0 + 0x79, 0x7b, 0x80, 0x38, 0x00, 0x68, 0xc9, 0x06, 0x01, 0xd5, 0x1d, 0x21, 0x00, 0xe0, 0x03, 0x21, /// 0x43d0 + 0x88, 0x42, 0x22, 0xd9, 0x08, 0x20, 0x28, 0x73, 0x32, 0x20, 0x30, 0x64, 0x01, 0x20, 0x15, 0xe0, /// 0x43e0 + 0x00, 0xf0, 0x7c, 0xf8, 0x02, 0x20, 0x11, 0xe0, 0x00, 0xf0, 0x7e, 0xf8, 0x03, 0x20, 0x0d, 0xe0, /// 0x43f0 + 0x00, 0xf0, 0x80, 0xf8, 0x04, 0x20, 0x09, 0xe0, 0xff, 0xf7, 0x32, 0xfe, 0x08, 0x48, 0x80, 0x38, /// 0x4400 + 0x00, 0x68, 0xf0, 0x63, 0xb0, 0x63, 0x1e, 0x20, 0x28, 0x73, 0x05, 0x20, 0xa0, 0x72, 0x04, 0xe0, /// 0x4410 + 0xff, 0xf7, 0x93, 0xfe, 0x01, 0xe0, 0x00, 0xf0, 0x73, 0xf8, 0x00, 0x20, 0xf8, 0xbd, 0x00, 0x00, /// 0x4420 + 0x80, 0x01, 0x00, 0x20, 0x40, 0x00, 0x00, 0x20, 0x20, 0x6c, 0x00, 0x40, 0x00, 0x34, 0x00, 0x40, /// 0x4430 + 0xa0, 0x00, 0x00, 0x20, 0xdc, 0x05, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, 0x20, 0x48, 0x00, 0x40, /// 0x4440 + 0x49, 0x02, 0x00, 0x00, 0x0d, 0x0b, 0x00, 0x20, 0x00, 0x44, 0x00, 0x40, 0x18, 0x11, 0x00, 0x20, /// 0x4450 + 0x7d, 0x0f, 0x00, 0x20, 0x27, 0x0f, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x4460 + 0x7f, 0x05, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x71, 0x05, 0x00, 0x00, /// 0x4470 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xe9, 0x15, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x4480 + 0x01, 0x90, 0x01, 0xbd, 0x15, 0x16, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x4490 + 0x2f, 0x07, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x2b, 0x12, 0x00, 0x00, /// 0x44a0 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xfd, 0x11, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x44b0 + 0x01, 0x90, 0x01, 0xbd, 0xd5, 0x05, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x44c0 + 0xf5, 0x03, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xb1, 0x00, 0x00, 0x00, /// 0x44d0 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x3d, 0x16, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x44e0 + 0x01, 0x90, 0x01, 0xbd, 0x81, 0x12, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x44f0 + 0x5d, 0x12, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x45, 0x12, 0x00, 0x00, /// 0x4500 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x6d, 0x11, 0x00, 0x00, 0xf8, 0xb5, 0x02, 0x22, /// 0x4510 + 0x03, 0x21, 0x00, 0x20, 0x00, 0xf0, 0x94, 0xfa, 0x03, 0x21, 0x00, 0xf0, 0x97, 0xfa, 0x05, 0x46, /// 0x4520 + 0xfe, 0x49, 0x00, 0xf0, 0x99, 0xfa, 0xfe, 0x4e, 0xfc, 0x49, 0x30, 0x80, 0x28, 0x39, 0x88, 0x69, /// 0x4530 + 0x0c, 0x46, 0x42, 0x00, 0x48, 0x69, 0x20, 0x34, 0xc3, 0x0f, 0x1a, 0x43, 0x8a, 0x61, 0xea, 0x07, /// 0x4540 + 0x40, 0x00, 0xd2, 0x0f, 0x10, 0x43, 0x48, 0x61, 0xa1, 0x7e, 0xf6, 0x4f, 0x49, 0x00, 0xc9, 0x19, /// 0x4550 + 0xff, 0x31, 0x01, 0x31, 0x0d, 0x85, 0x01, 0x22, 0x03, 0x21, 0x02, 0x20, 0x00, 0xf0, 0x70, 0xfa, /// 0x4560 + 0x45, 0x08, 0x21, 0x46, 0x14, 0x31, 0x28, 0x46, 0x00, 0xf0, 0x76, 0xfa, 0x70, 0x87, 0xa0, 0x7e, /// 0x4570 + 0x03, 0x22, 0x40, 0x00, 0xc0, 0x19, 0xff, 0x30, 0x01, 0x30, 0x85, 0x86, 0x11, 0x46, 0x01, 0x20, /// 0x4580 + 0x00, 0xf0, 0x5e, 0xfa, 0x03, 0x21, 0x00, 0xf0, 0x61, 0xfa, 0x21, 0x46, 0x05, 0x46, 0x0e, 0x31, /// 0x4590 + 0x00, 0xf0, 0x62, 0xfa, 0x31, 0x46, 0x40, 0x39, 0x88, 0x87, 0xa1, 0x7e, 0x49, 0x00, 0xc9, 0x19, /// 0x45a0 + 0xff, 0x31, 0x01, 0x31, 0xcd, 0x85, 0xa0, 0x7e, 0x02, 0x28, 0x01, 0xd3, 0x00, 0x20, 0x00, 0xe0, /// 0x45b0 + 0x40, 0x1c, 0xa0, 0x76, 0x00, 0x20, 0x60, 0x71, 0xf8, 0xbd, 0xf8, 0xb5, 0xd8, 0x4f, 0xda, 0x48, /// 0x45c0 + 0x39, 0x88, 0x81, 0x42, 0x05, 0xd2, 0xd9, 0x48, 0x02, 0x8b, 0x1f, 0x23, 0x1b, 0x02, 0x9a, 0x43, /// 0x45d0 + 0x02, 0x83, 0xd2, 0x4e, 0x88, 0x3e, 0x72, 0x7b, 0x35, 0x46, 0xd0, 0x07, 0x20, 0x3d, 0x00, 0x28, /// 0x45e0 + 0x60, 0xd0, 0x78, 0x8f, 0x00, 0xf0, 0x3e, 0xfa, 0xc0, 0x1c, 0xd1, 0x49, 0xb8, 0x80, 0x09, 0x78, /// 0x45f0 + 0xc9, 0x07, 0x59, 0xd1, 0x00, 0xf0, 0x3c, 0xfa, 0xcd, 0x48, 0xce, 0x4c, 0x40, 0x30, 0x80, 0x8f, /// 0x4600 + 0x6b, 0x38, 0x0b, 0x28, 0xb0, 0x7b, 0x32, 0xd3, 0xcb, 0x49, 0xc9, 0x7e, 0x49, 0x09, 0x88, 0x42, /// 0x4610 + 0x04, 0xd2, 0xa2, 0x88, 0x92, 0x07, 0x01, 0xd5, 0x01, 0x20, 0x05, 0xe0, 0x88, 0x42, 0x05, 0xd3, /// 0x4620 + 0xa1, 0x88, 0x89, 0x07, 0x02, 0xd4, 0x03, 0x20, 0xa0, 0x80, 0x38, 0xe0, 0x00, 0xf0, 0x26, 0xfa, /// 0x4630 + 0xb1, 0x7b, 0x0a, 0x29, 0x01, 0xd2, 0x00, 0x20, 0x08, 0xe0, 0x0f, 0x29, 0x01, 0xd2, 0x01, 0x20, /// 0x4640 + 0x04, 0xe0, 0x14, 0x29, 0x01, 0xd2, 0x02, 0x20, 0x00, 0xe0, 0x03, 0x20, 0x22, 0x88, 0xf0, 0x23, /// 0x4650 + 0x9a, 0x43, 0x80, 0x01, 0x02, 0x43, 0x22, 0x80, 0x02, 0x29, 0x01, 0xd9, 0x10, 0x20, 0x00, 0xe0, /// 0x4660 + 0x00, 0x20, 0xa0, 0x81, 0x38, 0x89, 0x00, 0xf0, 0x0f, 0xfa, 0x20, 0x82, 0x17, 0xe0, 0x09, 0x28, /// 0x4670 + 0x01, 0xd2, 0x01, 0x21, 0x00, 0xe0, 0x03, 0x21, 0xa1, 0x80, 0x21, 0x88, 0xf0, 0x22, 0x91, 0x43, /// 0x4680 + 0x12, 0x28, 0x01, 0xd2, 0x00, 0x22, 0x00, 0xe0, 0xc0, 0x22, 0x11, 0x43, 0x21, 0x80, 0x02, 0x28, /// 0x4690 + 0x01, 0xd9, 0x10, 0x21, 0x00, 0xe0, 0x00, 0x21, 0xa1, 0x81, 0x00, 0xf0, 0xef, 0xf9, 0x00, 0xf0, /// 0x46a0 + 0xf9, 0xf9, 0x01, 0xe0, 0x10, 0x07, 0x05, 0xd5, 0x00, 0xf0, 0xfa, 0xf9, 0x41, 0x1d, 0x0a, 0x29, /// 0x46b0 + 0x23, 0xd8, 0x25, 0xe0, 0x9e, 0x4b, 0x37, 0x20, 0x1c, 0x8e, 0x9a, 0x4b, 0xa1, 0x42, 0x1b, 0x68, /// 0x46c0 + 0x05, 0xd8, 0xe9, 0x6b, 0x7d, 0x24, 0x59, 0x1a, 0xe4, 0x00, 0xa1, 0x42, 0x15, 0xdb, 0x94, 0x48, /// 0x46d0 + 0x9a, 0x49, 0x40, 0x38, 0x80, 0x8f, 0x88, 0x42, 0x04, 0xd9, 0x94, 0x48, 0x81, 0x8a, 0x04, 0x15, /// 0x46e0 + 0x21, 0x43, 0x81, 0x82, 0x91, 0x48, 0x81, 0x8b, 0x01, 0x24, 0x21, 0x43, 0x81, 0x83, 0x05, 0x20, /// 0x46f0 + 0x02, 0x43, 0x72, 0x73, 0x28, 0x3b, 0xab, 0x63, 0xf8, 0xbd, 0x32, 0x21, 0x29, 0x64, 0x0f, 0xe0, /// 0x4700 + 0x71, 0x7b, 0x96, 0x22, 0xcb, 0x07, 0x00, 0x2b, 0x07, 0xd0, 0x84, 0x4b, 0x28, 0x3b, 0x59, 0x7f, /// 0x4710 + 0x00, 0x29, 0x04, 0xd0, 0x49, 0x1e, 0x59, 0x77, 0x02, 0xe0, 0x09, 0x07, 0x00, 0xd5, 0x2a, 0x64, /// 0x4720 + 0x83, 0x49, 0x81, 0x4b, 0x09, 0x8e, 0x3a, 0x3b, 0xcb, 0x18, 0x7c, 0x49, 0x3a, 0x88, 0x08, 0x39, /// 0x4730 + 0x9a, 0x42, 0x19, 0xd9, 0x0a, 0x79, 0x0a, 0x2a, 0x03, 0xd3, 0x7a, 0x48, 0x00, 0x68, 0xe8, 0x63, /// 0x4740 + 0xf8, 0xbd, 0x52, 0x1c, 0x0a, 0x71, 0xc3, 0x21, 0x89, 0x00, 0xa9, 0x81, 0xa8, 0x73, 0x00, 0x28, /// 0x4750 + 0x01, 0xd0, 0x01, 0x20, 0x70, 0x74, 0x01, 0x20, 0x00, 0xf0, 0xa8, 0xf9, 0x78, 0x48, 0x81, 0x89, /// 0x4760 + 0x80, 0x22, 0x51, 0x40, 0x81, 0x81, 0xf8, 0xbd, 0x00, 0x22, 0xeb, 0xe7, 0x6d, 0x4a, 0x10, 0xb5, /// 0x4770 + 0x0c, 0x23, 0x80, 0x32, 0x13, 0x73, 0xa4, 0x23, 0x53, 0x73, 0x90, 0x73, 0x69, 0x48, 0x08, 0x22, /// 0x4780 + 0x8f, 0x30, 0x00, 0xf0, 0x99, 0xf9, 0x0c, 0x20, 0x00, 0xf0, 0x90, 0xf9, 0x10, 0xbd, 0x70, 0xb5, /// 0x4790 + 0x64, 0x48, 0x67, 0x4c, 0x00, 0x68, 0x21, 0x6f, 0x6a, 0x4a, 0x41, 0x1a, 0x8a, 0xb0, 0x91, 0x42, /// 0x47a0 + 0x3e, 0xd9, 0xa1, 0x78, 0x68, 0x4e, 0x09, 0x07, 0x15, 0xd5, 0x25, 0x46, 0x40, 0x35, 0xea, 0x8f, /// 0x47b0 + 0x51, 0x1c, 0xe9, 0x87, 0x03, 0x2a, 0x10, 0xd9, 0x59, 0x48, 0x08, 0x22, 0x40, 0x38, 0x81, 0x8e, /// 0x47c0 + 0x11, 0x43, 0x81, 0x86, 0x10, 0x46, 0x00, 0xf0, 0x7d, 0xf9, 0xa0, 0x78, 0xf7, 0x21, 0x08, 0x40, /// 0x47d0 + 0xa0, 0x70, 0x00, 0x20, 0xe8, 0x87, 0x0a, 0xb0, 0x70, 0xbd, 0x5c, 0xa3, 0x0e, 0xcb, 0x01, 0xad, /// 0x47e0 + 0x0e, 0xc5, 0x4e, 0x49, 0x20, 0x67, 0x14, 0x39, 0x08, 0x22, 0x0c, 0x46, 0x04, 0xa8, 0x00, 0xf0, /// 0x47f0 + 0x63, 0xf9, 0x08, 0x22, 0x01, 0xa9, 0x06, 0xa8, 0x00, 0xf0, 0x5e, 0xf9, 0x30, 0x46, 0x00, 0xf0, /// 0x4800 + 0x67, 0xf9, 0x10, 0x22, 0x04, 0xa9, 0x30, 0x46, 0x00, 0xf0, 0x68, 0xf9, 0x48, 0x49, 0x30, 0x46, /// 0x4810 + 0x0c, 0x31, 0x00, 0xf0, 0x69, 0xf9, 0x21, 0x46, 0x08, 0x20, 0xff, 0xf7, 0xa7, 0xff, 0xda, 0xe7, /// 0x4820 + 0xff, 0xf7, 0xcb, 0xfe, 0x3d, 0x49, 0x28, 0x39, 0x48, 0x7f, 0x00, 0x28, 0xd3, 0xd0, 0x40, 0x1e, /// 0x4830 + 0x48, 0x77, 0xd0, 0xe7, 0xf8, 0xb5, 0x3e, 0x4d, 0x3d, 0x4c, 0x20, 0x35, 0x28, 0x7e, 0x38, 0x4b, /// 0x4840 + 0x40, 0x1e, 0xc2, 0xb2, 0x2a, 0x76, 0xa0, 0x8f, 0x19, 0x88, 0x08, 0x2a, 0x10, 0xd3, 0x95, 0x07, /// 0x4850 + 0x0d, 0xd1, 0x65, 0x8f, 0x69, 0x18, 0x89, 0xb2, 0x61, 0x87, 0x5b, 0x8f, 0xc0, 0x18, 0x80, 0xb2, /// 0x4860 + 0xa0, 0x87, 0x08, 0x2a, 0x03, 0xd1, 0x09, 0x09, 0x61, 0x87, 0x00, 0x09, 0xa0, 0x87, 0xf8, 0xbd, /// 0x4870 + 0x06, 0x2a, 0xfc, 0xd8, 0x00, 0xf0, 0xf6, 0xf8, 0x37, 0x49, 0x09, 0x88, 0x28, 0x4a, 0xc9, 0x05, /// 0x4880 + 0x20, 0x32, 0x00, 0x29, 0x01, 0xda, 0x11, 0x7d, 0x08, 0x18, 0x2a, 0x49, 0x0b, 0x8a, 0x1b, 0x04, /// 0x4890 + 0x02, 0xd5, 0x15, 0x23, 0xd3, 0x56, 0x18, 0x18, 0x62, 0x8f, 0x15, 0x23, 0x43, 0x43, 0x5a, 0x43, /// 0x48a0 + 0x8b, 0x88, 0x12, 0x0b, 0x00, 0x26, 0x01, 0x2b, 0x05, 0xd0, 0x55, 0x23, 0xdb, 0x00, 0x98, 0x42, /// 0x48b0 + 0x03, 0xd9, 0x05, 0x20, 0x05, 0xe0, 0x6e, 0x76, 0x04, 0xe0, 0x08, 0x88, 0x00, 0x06, 0x80, 0x0f, /// 0x48c0 + 0x40, 0x1c, 0x68, 0x76, 0x68, 0x7e, 0x41, 0x00, 0x15, 0x48, 0x40, 0x38, 0x09, 0x18, 0x60, 0x31, /// 0x48d0 + 0x08, 0x7a, 0x50, 0x43, 0xc2, 0x09, 0x09, 0x20, 0x08, 0x56, 0x0a, 0x21, 0x48, 0x43, 0x1f, 0x49, /// 0x48e0 + 0x80, 0x18, 0x01, 0xd5, 0x00, 0x20, 0x06, 0xe0, 0x88, 0x42, 0x04, 0xd9, 0x1b, 0x4a, 0x52, 0x42, /// 0x48f0 + 0x82, 0x18, 0xd2, 0x08, 0x10, 0x18, 0x0e, 0x4a, 0x40, 0x32, 0x92, 0x8f, 0x6b, 0x3a, 0x0a, 0x2a, /// 0x4900 + 0x01, 0xd8, 0x17, 0x4a, 0x80, 0x18, 0x17, 0x4a, 0x90, 0x42, 0x00, 0xd9, 0x10, 0x46, 0x0b, 0x4a, /// 0x4910 + 0x04, 0x4f, 0x3d, 0x32, 0x80, 0x37, 0xba, 0x81, 0xc0, 0x01, 0x25, 0xe0, 0x28, 0x02, 0x00, 0x20, /// 0x4920 + 0x40, 0x00, 0x00, 0x20, 0x00, 0x01, 0x00, 0x20, 0x83, 0x02, 0x00, 0x00, 0x00, 0x30, 0x00, 0x40, /// 0x4930 + 0x80, 0x00, 0x00, 0x20, 0x00, 0x34, 0x00, 0x40, 0x20, 0x06, 0x00, 0x20, 0xcf, 0x03, 0x00, 0x00, /// 0x4940 + 0x20, 0x6c, 0x00, 0x40, 0x70, 0x17, 0x00, 0x00, 0x40, 0x03, 0x00, 0x20, 0x58, 0x69, 0x61, 0x6f, /// 0x4950 + 0x6d, 0x69, 0x52, 0x78, 0x00, 0x00, 0x00, 0x00, 0x20, 0x38, 0x00, 0x40, 0x88, 0x13, 0x00, 0x00, /// 0x4960 + 0xdc, 0x05, 0x00, 0x00, 0xe8, 0x26, 0x00, 0x00, 0x00, 0xf0, 0x70, 0xf8, 0xb8, 0x73, 0x66, 0x87, /// 0x4970 + 0xa6, 0x87, 0x2e, 0x76, 0x01, 0x20, 0x00, 0xf0, 0x99, 0xf8, 0xf8, 0xbd, 0xf8, 0xb5, 0x2b, 0x4c, /// 0x4980 + 0xa0, 0x7b, 0x80, 0x06, 0x01, 0xd5, 0x00, 0xf0, 0xb5, 0xf8, 0xa0, 0x7b, 0x40, 0x06, 0x0a, 0xd5, /// 0x4990 + 0xe0, 0x7b, 0x5a, 0x28, 0x07, 0xd1, 0x60, 0x7b, 0xef, 0x21, 0x08, 0x40, 0x40, 0x21, 0x08, 0x43, /// 0x49a0 + 0x60, 0x73, 0x23, 0x48, 0x80, 0x47, 0xa0, 0x7b, 0x04, 0x27, 0xc1, 0x06, 0x21, 0x4d, 0x00, 0x29, /// 0x49b0 + 0x02, 0xda, 0x69, 0x78, 0x39, 0x43, 0x69, 0x70, 0x00, 0x07, 0x04, 0xd5, 0x1b, 0x48, 0x20, 0x38, /// 0x49c0 + 0xc0, 0x7e, 0x00, 0xf0, 0x9d, 0xf8, 0xa0, 0x7b, 0x08, 0x26, 0x80, 0x07, 0x00, 0x28, 0x15, 0xda, /// 0x49d0 + 0x19, 0x49, 0x48, 0x7b, 0x02, 0x07, 0x03, 0xd5, 0xf7, 0x22, 0x10, 0x40, 0x48, 0x73, 0x0d, 0xe0, /// 0x49e0 + 0x30, 0x43, 0x48, 0x73, 0x00, 0xf0, 0x92, 0xf8, 0x10, 0x48, 0x80, 0x22, 0x40, 0x38, 0x81, 0x8e, /// 0x49f0 + 0x91, 0x43, 0x81, 0x86, 0x11, 0x48, 0x81, 0x89, 0xb9, 0x43, 0x81, 0x81, 0xa0, 0x7b, 0xc1, 0x07, /// 0x4a00 + 0x02, 0xd0, 0x69, 0x78, 0x31, 0x43, 0x69, 0x70, 0x00, 0x06, 0x03, 0xd5, 0xa8, 0x78, 0x01, 0x21, /// 0x4a10 + 0x08, 0x43, 0xa8, 0x70, 0x20, 0x7b, 0xc0, 0x07, 0x02, 0xd0, 0xa8, 0x78, 0x30, 0x43, 0xa8, 0x70, /// 0x4a20 + 0x00, 0x20, 0xe0, 0x73, 0x20, 0x73, 0xa0, 0x73, 0xf8, 0xbd, 0x00, 0x00, 0x40, 0x00, 0x00, 0x20, /// 0x4a30 + 0x61, 0x06, 0x00, 0x20, 0x80, 0x00, 0x00, 0x20, 0xa0, 0x01, 0x00, 0x20, 0x20, 0x6c, 0x00, 0x40, /// 0x4a40 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xcb, 0x03, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x4a50 + 0x01, 0x90, 0x01, 0xbd, 0xe9, 0x15, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x4a60 + 0x49, 0x04, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x9d, 0x04, 0x00, 0x00, /// 0x4a70 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x7d, 0x08, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x4a80 + 0x01, 0x90, 0x01, 0xbd, 0x6b, 0x04, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x4a90 + 0xbf, 0x11, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x39, 0x08, 0x00, 0x00, /// 0x4aa0 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0x97, 0x11, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x4ab0 + 0x01, 0x90, 0x01, 0xbd, 0x2f, 0x07, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x4ac0 + 0x7f, 0x05, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xd5, 0x05, 0x00, 0x00, /// 0x4ad0 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xe5, 0x12, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x4ae0 + 0x01, 0x90, 0x01, 0xbd, 0x71, 0x15, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, /// 0x4af0 + 0x15, 0x15, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xef, 0x05, 0x00, 0x00, /// 0x4b00 + 0x03, 0xb4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xbd, 0xa3, 0x12, 0x00, 0x00, 0x03, 0xb4, 0x01, 0x48, /// 0x4b10 + 0x01, 0x90, 0x01, 0xbd, 0x05, 0x0f, 0x00, 0x00, 0x32, 0x33, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, /// 0x4b20 + 0xf0, 0x14, 0xac, 0x28, 0xac, 0x28, 0xac, 0x28, 0xbe, 0x28, 0xb9, 0x28, 0x14, 0x14, 0x00, 0x00, +}; +#endif + +extern uint32_t get_hw_version_major(void); + +#endif diff --git a/drivers/power/supply/qcom/pmic-voter.c b/drivers/power/supply/qcom/pmic-voter.c index 54ef3eeb488c..5334b50d5331 100644 --- a/drivers/power/supply/qcom/pmic-voter.c +++ b/drivers/power/supply/qcom/pmic-voter.c @@ -1,4 +1,5 @@ /* Copyright (c) 2015-2017, 2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and diff --git a/drivers/power/supply/qcom/qpnp-fg-gen4.c b/drivers/power/supply/qcom/qpnp-fg-gen4.c index c98fb2c2b2a4..de50d11278b8 100644 --- a/drivers/power/supply/qcom/qpnp-fg-gen4.c +++ b/drivers/power/supply/qcom/qpnp-fg-gen4.c @@ -1,4 +1,5 @@ /* Copyright (c) 2018-2019, The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -23,6 +24,7 @@ #include #include #include +#include #include "fg-core.h" #include "fg-reg.h" #include "fg-alg.h" @@ -886,6 +888,18 @@ static int fg_gen4_get_prop_capacity(struct fg_dev *fg, int *val) return 0; } + rc = fg_get_msoc(fg, &msoc); + if (rc < 0) + return rc; + + if (fg->empty_restart_fg && (msoc == 0)) + msoc = EMPTY_REPORT_SOC; + + if (chip->dt.linearize_soc && fg->delta_soc > 0) + *val = fg->maint_soc; + else + *val = msoc; + if (chip->soc_scale_mode) { mutex_lock(&chip->soc_scale_lock); *val = chip->soc_scale_msoc; @@ -1689,6 +1703,13 @@ static int fg_gen4_get_batt_profile(struct fg_dev *fg) fg->bp.vbatt_full_mv = -EINVAL; } + rc = of_property_read_u32(profile_node, "qcom,nom-batt-capacity-mah", + &fg->bp.nom_cap_uah); + if (rc < 0) { + pr_err("battery nominal capacity unavailable, rc:%d\n", rc); + fg->bp.nom_cap_uah = -EINVAL; + } + if (of_find_property(profile_node, "qcom,therm-coefficients", &len)) { len /= sizeof(u32); if (len == BATT_THERM_NUM_COEFFS) { @@ -2618,6 +2639,8 @@ static int fg_gen4_adjust_recharge_soc(struct fg_gen4_chip *chip) if (is_input_present(fg)) { if (fg->charge_done) { if (!fg->recharge_soc_adjusted) { + if (fg->health == POWER_SUPPLY_HEALTH_GOOD) + return 0; /* Get raw monotonic SOC for calculation */ rc = fg_get_msoc(fg, &msoc); if (rc < 0) { @@ -3310,6 +3333,20 @@ static irqreturn_t fg_vbatt_low_irq_handler(int irq, void *data) if (vbatt_mv < chip->dt.cutoff_volt_mv) { if (chip->dt.rapid_soc_dec_en) { + /* + * Set vbat_low debounce window to avoid shutdown in low temperature and high + * current scene, we set the counter to maxium 5, if fg_vbatt_low_irq trigger + * exceed 5 times, decrease soc to 0% very rapidly. + */ + fg->vbat_critical_low_count++; + if (fg->vbat_critical_low_count < EMPTY_DEBOUNCE_TIME_COUNT_MAX + && vbatt_mv > VBAT_CRITICAL_LOW_THR) { + pr_info("fg->vbat_critical_low_count:%d\n", + fg->vbat_critical_low_count); + if (batt_psy_initialized(fg)) + power_supply_changed(fg->batt_psy); + return IRQ_HANDLED; + } /* * Set this flag so that slope limiter coefficient * cannot be configured during rapid SOC decrease. @@ -3456,6 +3493,30 @@ static irqreturn_t fg_delta_bsoc_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static bool fg_is_input_suspend(struct fg_dev *fg) +{ + int rc = 0; + union power_supply_propval prop = {0, }; + int input_suspend = 0; + + if (fg->batt_psy) { + rc = power_supply_get_property(fg->batt_psy, + POWER_SUPPLY_PROP_INPUT_SUSPEND, + &prop); + if (rc < 0) { + pr_err("Error in getting input suspend property, rc=%d\n", rc); + return false; + } + input_suspend = prop.intval; + } + + if (input_suspend == 1) + return true; + else + return false; +} + + #define CENTI_FULL_SOC 10000 static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) { @@ -3463,6 +3524,7 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); int rc, batt_soc, batt_temp, msoc_raw; bool input_present = is_input_present(fg); + bool input_suspend = false; u32 batt_soc_cp; rc = fg_get_msoc_raw(fg, &msoc_raw); @@ -3472,12 +3534,15 @@ static irqreturn_t fg_delta_msoc_irq_handler(int irq, void *data) get_batt_psy_props(fg); + input_suspend = fg_is_input_suspend(fg); + rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &batt_soc); if (rc < 0) pr_err("Failed to read battery soc rc: %d\n", rc); else cycle_count_update(chip->counter, (u32)batt_soc >> 24, - fg->charge_status, fg->charge_done, input_present); + fg->charge_status, fg->charge_done, + (input_present & (!input_suspend))); rc = fg_gen4_get_battery_temp(fg, &batt_temp); if (rc < 0) { @@ -3890,6 +3955,8 @@ static void pl_current_en_work(struct work_struct *work) return; vote(chip->parallel_current_en_votable, FG_PARALLEL_EN_VOTER, en, 0); + + vote(chip->mem_attn_irq_en_votable, MEM_ATTN_IRQ_VOTER, false, 0); } static void pl_enable_work(struct work_struct *work) @@ -3911,8 +3978,9 @@ static void status_change_work(struct work_struct *work) struct fg_dev *fg = container_of(work, struct fg_dev, status_change_work); struct fg_gen4_chip *chip = container_of(fg, struct fg_gen4_chip, fg); - int rc, batt_soc, batt_temp; + int rc, batt_soc, batt_temp, msoc_raw; bool input_present, qnovo_en; + bool input_suspend = false; u32 batt_soc_cp; if (fg->battery_missing) { @@ -3938,6 +4006,16 @@ static void status_change_work(struct work_struct *work) get_batt_psy_props(fg); + if (fg->charge_done && !fg->report_full) { + fg->report_full = true; + } else if (!fg->charge_done && fg->report_full) { + rc = fg_get_msoc_raw(fg, &msoc_raw); + if (rc < 0) + pr_err("Error in getting msoc, rc=%d\n", rc); + if (msoc_raw < FULL_SOC_REPORT_THR - 4) + fg->report_full = false; + } + rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &batt_soc); if (rc < 0) { pr_err("Failed to read battery soc rc: %d\n", rc); @@ -3951,9 +4029,12 @@ static void status_change_work(struct work_struct *work) } input_present = is_input_present(fg); + fg->input_present = input_present; + input_suspend = fg_is_input_suspend(fg); qnovo_en = is_qnovo_en(fg); cycle_count_update(chip->counter, (u32)batt_soc >> 24, - fg->charge_status, fg->charge_done, input_present); + fg->charge_status, fg->charge_done, + (input_present & (!input_suspend))); if (fg->charge_status != fg->prev_charge_status) { batt_soc_cp = div64_u64((u64)(u32)batt_soc * CENTI_FULL_SOC, @@ -4254,9 +4335,13 @@ static int fg_psy_get_property(struct power_supply *psy, pval->intval = (int)temp; break; case POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN: - rc = fg_gen4_get_nominal_capacity(chip, &temp); - if (!rc) - pval->intval = (int)temp; + if (-EINVAL != fg->bp.nom_cap_uah) { + pval->intval = fg->bp.nom_cap_uah * 1000; + } else { + rc = fg_gen4_get_nominal_capacity(chip, &temp); + if (!rc) + pval->intval = (int)temp; + } break; case POWER_SUPPLY_PROP_CHARGE_COUNTER: rc = fg_gen4_get_charge_counter(chip, &pval->intval); @@ -4390,6 +4475,10 @@ static int fg_psy_set_property(struct power_supply *psy, if (chip->sp) soh_profile_update(chip->sp, chip->soh); break; + case POWER_SUPPLY_PROP_CYCLE_COUNT: + rc = set_cycle_count(chip->counter, pval->intval); + pr_info("Cycle count is modified to %d by userspace\n", pval->intval); + break; case POWER_SUPPLY_PROP_CLEAR_SOH: if (chip->first_profile_load && !pval->intval) { fg_dbg(fg, FG_STATUS, "Clearing first profile load bit\n"); @@ -4413,6 +4502,11 @@ static int fg_psy_set_property(struct power_supply *psy, chip->batt_age_level = pval->intval; schedule_delayed_work(&fg->profile_load_work, 0); break; + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: + if (fg->vbatt_full_volt_uv != pval->intval) + rc = fg_set_constant_chg_voltage(fg, pval->intval); + fg->vbatt_full_volt_uv = pval->intval; + break; case POWER_SUPPLY_PROP_CALIBRATE: rc = fg_gen4_set_calibrate_level(chip, pval->intval); break; @@ -4433,8 +4527,10 @@ static int fg_property_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_ESR_ACTUAL: case POWER_SUPPLY_PROP_ESR_NOMINAL: case POWER_SUPPLY_PROP_SOH: + case POWER_SUPPLY_PROP_CYCLE_COUNT: case POWER_SUPPLY_PROP_CLEAR_SOH: case POWER_SUPPLY_PROP_BATT_AGE_LEVEL: + case POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE: case POWER_SUPPLY_PROP_CALIBRATE: return 1; default: @@ -4466,6 +4562,7 @@ static enum power_supply_property fg_psy_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_CHARGE_COUNTER, POWER_SUPPLY_PROP_CHARGE_COUNTER_SHADOW, + POWER_SUPPLY_PROP_CYCLE_COUNT, POWER_SUPPLY_PROP_CYCLE_COUNTS, POWER_SUPPLY_PROP_SOC_REPORTING_READY, POWER_SUPPLY_PROP_CLEAR_SOH, @@ -5360,7 +5457,7 @@ static int fg_gen4_parse_nvmem_dt(struct fg_gen4_chip *chip) #define DEFAULT_CL_MAX_LIM_DECIPERC 0 #define DEFAULT_CL_DELTA_BATT_SOC 10 #define BTEMP_DELTA_LOW 0 -#define BTEMP_DELTA_HIGH 3 +#define BTEMP_DELTA_HIGH 10 #define DEFAULT_ESR_PULSE_THRESH_MA 47 #define DEFAULT_ESR_MEAS_CURR_MA 120 #define DEFAULT_SCALE_VBATT_THR_MV 3400 @@ -5686,6 +5783,116 @@ static int fg_gen4_parse_dt(struct fg_gen4_chip *chip) return 0; } +#define SOC_WORK_MS 20000 +static void soc_work_fn(struct work_struct *work) +{ + struct fg_dev *fg = container_of(work, + struct fg_dev, soc_work.work); + struct fg_gen4_chip *chip = container_of(fg, + struct fg_gen4_chip, fg); + int msoc = 0, soc = 0, curr_ua = 0, volt_uv = 0, temp = 0; + int esr_uohms = 0; + int cycle_count; + int rc; + static int prev_soc = -EINVAL; + + rc = fg_gen4_get_prop_capacity(fg, &soc); + if (rc < 0) + pr_err("Error in getting capacity, rc=%d\n", rc); + + rc = fg_get_msoc_raw(fg, &msoc); + if (rc < 0) + pr_err("Error in getting msoc, rc=%d\n", rc); + + rc = fg_get_battery_resistance(fg, &esr_uohms); + if (rc < 0) + pr_err("Error in getting esr_uohms, rc=%d\n", rc); + + fg_get_battery_current(fg, &curr_ua); + if (rc < 0) + pr_err("failed to get current, rc=%d\n", rc); + + rc = fg_get_battery_voltage(fg, &volt_uv); + if (rc < 0) + pr_err("failed to get voltage, rc=%d\n", rc); + + rc = fg_gen4_get_battery_temp(fg, &temp); + if (rc < 0) + pr_err("Error in getting batt_temp, rc=%d\n", rc); + + rc = get_cycle_count(chip->counter, &cycle_count); + if (rc < 0) + pr_err("failed to get cycle count, rc=%d\n", rc); + + pr_info("adjust_soc: s %d r %d i %d v %d t %d cc %d m 0x%02x\n", + soc, + esr_uohms, + curr_ua/1000, + volt_uv/1000, + temp, + cycle_count, + msoc); + + if (temp < 450 && fg->last_batt_temp >= 450) { + /* follow the way that fg_notifier_cb use wake lock */ + pm_stay_awake(fg->dev); + schedule_work(&fg->status_change_work); + } + + fg->last_batt_temp = temp; + + /* if soc changes, report power supply changed uevent */ + if (soc != prev_soc) { + if (fg->batt_psy) + power_supply_changed(fg->batt_psy); + prev_soc = soc; + } + + schedule_delayed_work( + &fg->soc_work, + msecs_to_jiffies(SOC_WORK_MS)); +} + +static void empty_restart_fg_work(struct work_struct *work) +{ + struct fg_dev *fg = container_of(work, struct fg_dev, + empty_restart_fg_work.work); + union power_supply_propval prop = {0, }; + int usb_present = 0; + int rc; + + if (usb_psy_initialized(fg)) { + rc = power_supply_get_property(fg->usb_psy, + POWER_SUPPLY_PROP_PRESENT, &prop); + if (rc < 0) { + pr_err("Couldn't read usb present prop rc=%d\n", rc); + return; + } + usb_present = prop.intval; + } + + /* only when usb is absent, restart fg */ + if (!usb_present) { + if (fg->profile_load_status == PROFILE_LOADED) { + pr_info("soc empty after cold to warm, need to restart fg\n"); + fg->empty_restart_fg = true; + rc = fg_restart(fg, SOC_READY_WAIT_TIME_MS); + if (rc < 0) { + pr_err("Error in restarting FG, rc=%d\n", rc); + fg->empty_restart_fg = false; + return; + } + pr_info("FG restart done\n"); + if (batt_psy_initialized(fg)) + power_supply_changed(fg->batt_psy); + } else { + schedule_delayed_work( + &fg->empty_restart_fg_work, + msecs_to_jiffies(RESTART_FG_WORK_MS)); + } + } +} + static void fg_gen4_cleanup(struct fg_gen4_chip *chip) { struct fg_dev *fg = &chip->fg; @@ -5697,7 +5904,9 @@ static void fg_gen4_cleanup(struct fg_gen4_chip *chip) fg_gen4_exit_soc_scale(chip); cancel_delayed_work_sync(&fg->profile_load_work); + cancel_delayed_work_sync(&fg->empty_restart_fg_work); cancel_delayed_work_sync(&fg->sram_dump_work); + cancel_delayed_work_sync(&fg->soc_work); cancel_work_sync(&chip->pl_current_en_work); power_supply_unreg_notifier(&fg->nb); @@ -5771,6 +5980,8 @@ static int fg_gen4_probe(struct platform_device *pdev) chip->ki_coeff_full_soc[0] = -EINVAL; chip->ki_coeff_full_soc[1] = -EINVAL; chip->esr_soh_cycle_count = -EINVAL; + fg->vbat_critical_low_count = 0; + fg->vbatt_full_volt_uv = 0; chip->calib_level = -EINVAL; fg->regmap = dev_get_regmap(fg->dev->parent, NULL); if (!fg->regmap) { @@ -5790,6 +6001,8 @@ static int fg_gen4_probe(struct platform_device *pdev) INIT_WORK(&chip->soc_scale_work, soc_scale_work); INIT_DELAYED_WORK(&fg->profile_load_work, profile_load_work); INIT_DELAYED_WORK(&fg->sram_dump_work, sram_dump_work); + INIT_DELAYED_WORK(&fg->soc_work, soc_work_fn); + INIT_DELAYED_WORK(&fg->empty_restart_fg_work, empty_restart_fg_work); INIT_DELAYED_WORK(&chip->pl_enable_work, pl_enable_work); INIT_WORK(&chip->pl_current_en_work, pl_current_en_work); @@ -5968,6 +6181,13 @@ static int fg_gen4_probe(struct platform_device *pdev) fg_gen4_post_init(chip); + schedule_delayed_work(&fg->soc_work, 0); + + if ((volt_uv >= VBAT_RESTART_FG_EMPTY_UV) + && (msoc == 0) && (batt_temp >= TEMP_THR_RESTART_FG)) + schedule_delayed_work(&fg->empty_restart_fg_work, + msecs_to_jiffies(RESTART_FG_START_WORK_MS)); + pr_debug("FG GEN4 driver probed successfully\n"); return 0; exit: @@ -5987,7 +6207,7 @@ static void fg_gen4_shutdown(struct platform_device *pdev) { struct fg_gen4_chip *chip = dev_get_drvdata(&pdev->dev); struct fg_dev *fg = &chip->fg; - int rc, bsoc; + int rc, bsoc, msoc; fg_unregister_interrupts(fg, chip, FG_GEN4_IRQ_MAX); @@ -6001,13 +6221,19 @@ static void fg_gen4_shutdown(struct platform_device *pdev) rc); } + rc = fg_gen4_get_prop_capacity(fg, &msoc); + if (rc < 0) { + pr_err("Error in getting capacity, rc=%d\n", rc); + return; + } + rc = fg_get_sram_prop(fg, FG_SRAM_BATT_SOC, &bsoc); if (rc < 0) { pr_err("Error in getting BATT_SOC, rc=%d\n", rc); return; } - if (fg->charge_full) { + if (fg->charge_full || (msoc == 100)) { /* We need 2 most significant bytes here */ bsoc = (u32)bsoc >> 16; @@ -6031,6 +6257,7 @@ static int fg_gen4_suspend(struct device *dev) struct fg_gen4_chip *chip = dev_get_drvdata(dev); struct fg_dev *fg = &chip->fg; + cancel_delayed_work_sync(&fg->soc_work); cancel_delayed_work_sync(&chip->ttf->ttf_work); if (fg_sram_dump) cancel_delayed_work_sync(&fg->sram_dump_work); @@ -6042,6 +6269,8 @@ static int fg_gen4_resume(struct device *dev) struct fg_gen4_chip *chip = dev_get_drvdata(dev); struct fg_dev *fg = &chip->fg; + schedule_delayed_work( + &fg->soc_work, msecs_to_jiffies(SOC_WORK_MS)); schedule_delayed_work(&chip->ttf->ttf_work, 0); if (fg_sram_dump) schedule_delayed_work(&fg->sram_dump_work, diff --git a/drivers/power/supply/qcom/qpnp-smb5.c b/drivers/power/supply/qcom/qpnp-smb5.c index 8475532b2dcb..736c633a6daa 100644 --- a/drivers/power/supply/qcom/qpnp-smb5.c +++ b/drivers/power/supply/qcom/qpnp-smb5.c @@ -1,4 +1,5 @@ /* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -73,6 +74,13 @@ static struct smb_params smb5_pmi632_params = { .max_u = 1000000, .step_u = 250000, }, + .dc_icl = { + .name = "DC input current limit", + .reg = DCDC_CFG_REF_MAX_PSNS_REG, + .min_u = 0, + .max_u = 1500000, + .step_u = 50000, + }, .jeita_cc_comp_hot = { .name = "jeita fcc reduction", .reg = JEITA_CCCOMP_CFG_HOT_REG, @@ -161,7 +169,7 @@ static struct smb_params smb5_pm8150b_params = { .reg = DCDC_CFG_REF_MAX_PSNS_REG, .min_u = 0, .max_u = DCIN_ICL_MAX_UA, - .step_u = 50000, + .step_u = 40000, }, .jeita_cc_comp_hot = { .name = "jeita fcc reduction", @@ -207,6 +215,7 @@ static struct smb_params smb5_pm8150b_params = { struct smb_dt_props { int usb_icl_ua; + int dc_icl_ua; struct device_node *revid_dev_node; enum float_options float_option; int chg_inhibit_thr_mv; @@ -255,6 +264,24 @@ enum { SMB_THERM, }; +static int smb5_get_prop_input_voltage_regulation(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + chg->idtp_psy = power_supply_get_by_name("idt"); + if (chg->idtp_psy) + chg->wls_chip_psy = chg->idtp_psy; + + if (chg->wls_chip_psy) + rc = power_supply_get_property(chg->wls_chip_psy, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, val); + + val->intval = 1000*val->intval;//IDT in mV + + return rc; +} + static const struct clamp_config clamp_levels[] = { { {0x11C6, 0x11F9, 0x13F1}, {0x60, 0x2E, 0x90} }, { {0x11C6, 0x11F9, 0x13F1}, {0x60, 0x2B, 0x9C} }, @@ -333,9 +360,6 @@ static int smb5_chg_config_init(struct smb5 *chip) chg->chg_freq.freq_below_otg_threshold = 800; chg->chg_freq.freq_above_otg_threshold = 800; - if (of_property_read_bool(node, "qcom,disable-sw-thermal-regulation")) - chg->wa_flags &= ~SW_THERM_REGULATION_WA; - if (of_property_read_bool(node, "qcom,disable-fcc-restriction")) chg->main_fcc_max = -EINVAL; @@ -383,9 +407,18 @@ static int smb5_configure_internal_pull(struct smb_charger *chg, int type, return rc; } +int smblib_change_psns_to_curr(struct smb_charger *chg, int uv) +{ + dev_info(chg->dev, "get Vpsns = %d uV \n", uv); + uv = uv * PSNS_CURRENT_SAMPLE_RATE / PSNS_CURRENT_SAMPLE_RESIS; + + return uv; +} + #define MICRO_1P5A 1500000 #define MICRO_P1A 100000 #define MICRO_1PA 1000000 +#define MICRO_1P8A_FOR_DCP 1800000 #define MICRO_3PA 3000000 #define OTG_DEFAULT_DEGLITCH_TIME_MS 50 #define DEFAULT_WD_BARK_TIME 64 @@ -426,6 +459,17 @@ static int smb5_parse_dt(struct smb5 *chip) of_property_read_bool(node, "qcom,usb-pd-disable"); chg->lpd_disabled = of_property_read_bool(node, "qcom,lpd-disable"); + chg->lpd_enabled = of_property_read_bool(node, + "qcom,lpd-enable"); + + chg->dynamic_fv_enabled = of_property_read_bool(node, + "qcom,dynamic-fv-enable"); + + chg->qc_class_ab = of_property_read_bool(node, + "qcom,distinguish-qc-class-ab"); + + chg->support_wireless = of_property_read_bool(node, + "qcom,support-wireless"); rc = of_property_read_u32(node, "qcom,wd-bark-time-secs", &chip->dt.wd_bark_time); @@ -455,6 +499,11 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) chip->dt.usb_icl_ua = -EINVAL; + rc = of_property_read_u32(node, + "qcom,dc-icl-ua", &chip->dt.dc_icl_ua); + if (rc < 0) + chip->dt.dc_icl_ua = -EINVAL; + rc = of_property_read_u32(node, "qcom,otg-cl-ua", &chg->otg_cl_ua); if (rc < 0) @@ -474,6 +523,272 @@ static int smb5_parse_dt(struct smb5 *chip) rc = of_property_read_u32(node, "qcom,chg-term-base-current-ma", &chip->dt.term_current_thresh_lo_ma); + if (of_find_property(node, "qcom,lpd_hwversion", &byte_len)) { + chg->lpd_hwversion = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->lpd_hwversion == NULL) + return -ENOMEM; + + chg->lpd_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,lpd_hwversion", + chg->lpd_hwversion, + byte_len / sizeof(u32)); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } +#ifdef CONFIG_THERMAL + if (of_find_property(node, "qcom,thermal-mitigation-dcp", &byte_len)) { + chg->thermal_mitigation_dcp = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_dcp == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-dcp", + chg->thermal_mitigation_dcp, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-dc", &byte_len)) { + chg->thermal_mitigation_dc = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_dc == NULL) + return -ENOMEM; + + chg->dc_thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-dc", + chg->thermal_mitigation_dc, + chg->dc_thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-epp", &byte_len)) { + chg->thermal_mitigation_epp = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_epp == NULL) + return -ENOMEM; + + chg->dc_thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-epp", + chg->thermal_mitigation_epp, + chg->dc_thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-bpp-qc3", &byte_len)) { + chg->thermal_mitigation_bpp_qc3 = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_bpp_qc3 == NULL) + return -ENOMEM; + + chg->dc_thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-bpp-qc3", + chg->thermal_mitigation_bpp_qc3, + chg->dc_thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-bpp-qc2", &byte_len)) { + chg->thermal_mitigation_bpp_qc2 = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_bpp_qc2 == NULL) + return -ENOMEM; + + chg->dc_thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-bpp-qc2", + chg->thermal_mitigation_bpp_qc2, + chg->dc_thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-bpp", &byte_len)) { + chg->thermal_mitigation_bpp = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_bpp == NULL) + return -ENOMEM; + + chg->dc_thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-bpp", + chg->thermal_mitigation_bpp, + chg->dc_thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-qc2", &byte_len)) { + chg->thermal_mitigation_qc2 = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_qc2 == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-qc2", + chg->thermal_mitigation_qc2, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-pd-base", &byte_len)) { + chg->thermal_mitigation_pd_base = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_pd_base == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-pd-base", + chg->thermal_mitigation_pd_base, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-fcc-qc3-normal", &byte_len)) { + chg->thermal_fcc_qc3_normal = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_fcc_qc3_normal == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-fcc-qc3-normal", + chg->thermal_fcc_qc3_normal, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-fcc-qc3-cp", &byte_len)) { + chg->thermal_fcc_qc3_cp = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_fcc_qc3_cp == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-fcc-qc3-cp", + chg->thermal_fcc_qc3_cp, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-fcc-qc3-classb-cp", &byte_len)) { + chg->thermal_fcc_qc3_classb_cp = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_fcc_qc3_classb_cp == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-fcc-qc3-classb-cp", + chg->thermal_fcc_qc3_classb_cp, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-fcc-pps-cp", &byte_len)) { + chg->thermal_fcc_pps_cp = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_fcc_pps_cp == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-fcc-pps-cp", + chg->thermal_fcc_pps_cp, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } + + if (of_find_property(node, "qcom,thermal-mitigation-icl", &byte_len)) { + chg->thermal_mitigation_icl = devm_kzalloc(chg->dev, byte_len, + GFP_KERNEL); + + if (chg->thermal_mitigation_icl == NULL) + return -ENOMEM; + + chg->thermal_levels = byte_len / sizeof(u32); + rc = of_property_read_u32_array(node, + "qcom,thermal-mitigation-icl", + chg->thermal_mitigation_icl, + chg->thermal_levels); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't read threm limits rc = %d\n", rc); + return rc; + } + } +#else if (of_find_property(node, "qcom,thermal-mitigation", &byte_len)) { chg->thermal_mitigation = devm_kzalloc(chg->dev, byte_len, GFP_KERNEL); @@ -492,6 +807,7 @@ static int smb5_parse_dt(struct smb5 *chip) return rc; } } +#endif rc = of_property_read_u32(node, "qcom,charger-temp-max", &chg->charger_temp_max); @@ -543,7 +859,7 @@ static int smb5_parse_dt(struct smb5 *chip) return -EINVAL; } - chg->dcp_icl_ua = chip->dt.usb_icl_ua; + chg->dcp_icl_ua = MICRO_1P8A_FOR_DCP; chg->suspend_input_on_debug_batt = of_property_read_bool(node, "qcom,suspend-input-on-debug-batt"); @@ -585,6 +901,11 @@ static int smb5_parse_dt(struct smb5 *chip) "qcom,adc-based-aicl"); /* Extract ADC channels */ + rc = smblib_get_iio_channel(chg, "usb_in_voltage", + &chg->iio.usbin_v_chan); + if (rc < 0) + return rc; + rc = smblib_get_iio_channel(chg, "mid_voltage", &chg->iio.mid_chan); if (rc < 0) return rc; @@ -628,6 +949,14 @@ static int smb5_parse_dt(struct smb5 *chip) if (rc < 0) return rc; + rc = smblib_get_iio_channel(chg, "hw_version_gpio5", &chg->iio.hw_version_gpio5); + if (rc < 0) + return rc; + + rc = smblib_get_iio_channel(chg, "project_gpio6", &chg->iio.project_gpio6); + if (rc < 0) + return rc; + chip->dt.disable_suspend_on_collapse = of_property_read_bool(node, "qcom,disable-suspend-on-collapse"); @@ -704,6 +1033,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_TYPEC_CC_ORIENTATION, POWER_SUPPLY_PROP_LOW_POWER, POWER_SUPPLY_PROP_PD_ACTIVE, + POWER_SUPPLY_PROP_PD_AUTHENTICATION, POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED, POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, POWER_SUPPLY_PROP_BOOST_CURRENT, @@ -711,6 +1041,9 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_CTM_CURRENT_MAX, POWER_SUPPLY_PROP_HW_CURRENT_MAX, POWER_SUPPLY_PROP_REAL_TYPE, + POWER_SUPPLY_PROP_HVDCP3_TYPE, + POWER_SUPPLY_PROP_QUICK_CHARGE_TYPE, + POWER_SUPPLY_PROP_PR_SWAP, POWER_SUPPLY_PROP_PD_VOLTAGE_MAX, POWER_SUPPLY_PROP_PD_VOLTAGE_MIN, POWER_SUPPLY_PROP_CONNECTOR_TYPE, @@ -720,6 +1053,7 @@ static enum power_supply_property smb5_usb_props[] = { POWER_SUPPLY_PROP_VOLTAGE_MAX_LIMIT, POWER_SUPPLY_PROP_SMB_EN_MODE, POWER_SUPPLY_PROP_SMB_EN_REASON, + POWER_SUPPLY_PROP_TYPE_RECHECK, POWER_SUPPLY_PROP_ADAPTER_CC_MODE, POWER_SUPPLY_PROP_SCOPE, POWER_SUPPLY_PROP_MOISTURE_DETECTED, @@ -747,6 +1081,11 @@ static int smb5_usb_get_prop(struct power_supply *psy, rc = smblib_get_prop_usb_present(chg, val); break; case POWER_SUPPLY_PROP_ONLINE: + if (chg->report_usb_absent) { + val->intval = 0; + break; + } + rc = smblib_get_prop_usb_online(chg, val); if (!val->intval) break; @@ -788,6 +1127,21 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_REAL_TYPE: val->intval = chg->real_charger_type; break; + case POWER_SUPPLY_PROP_HVDCP3_TYPE: + if (chg->real_charger_type != POWER_SUPPLY_TYPE_USB_HVDCP_3) + val->intval = HVDCP3_NONE; /* 0: none hvdcp3 insert */ + else { + if (chg->is_qc_class_a) + val->intval = HVDCP3_CLASSA_18W; /* 18W hvdcp3 insert */ + else if (chg->is_qc_class_b) + val->intval = HVDCP3_CLASSB_27W; /* 27W hvdcp3 insert */ + else + val->intval = HVDCP3_NONE; + } + break; + case POWER_SUPPLY_PROP_QUICK_CHARGE_TYPE: + val->intval = smblib_get_quick_charge_type(chg); + break; case POWER_SUPPLY_PROP_TYPEC_MODE: if (chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB) val->intval = POWER_SUPPLY_TYPEC_NONE; @@ -818,6 +1172,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PD_ACTIVE: val->intval = chg->pd_active; break; + case POWER_SUPPLY_PROP_PD_AUTHENTICATION: + val->intval = chg->pd_verifed; + break; case POWER_SUPPLY_PROP_INPUT_CURRENT_SETTLED: rc = smblib_get_prop_input_current_settled(chg, val); break; @@ -881,6 +1238,9 @@ static int smb5_usb_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_SMB_EN_REASON: val->intval = chg->cp_reason; break; + case POWER_SUPPLY_PROP_TYPE_RECHECK: + rc = smblib_get_prop_type_recheck(chg, val); + break; case POWER_SUPPLY_PROP_MOISTURE_DETECTED: val->intval = chg->moisture_present; break; @@ -949,6 +1309,11 @@ static int smb5_usb_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_PD_ACTIVE: rc = smblib_set_prop_pd_active(chg, val); break; + case POWER_SUPPLY_PROP_PD_AUTHENTICATION: + chg->pd_verifed = val->intval; + rc = vote(chg->usb_icl_votable, PD_VERIFED_VOTER, + !chg->pd_verifed, PD_UNVERIFED_CURRENT); + break; case POWER_SUPPLY_PROP_PD_IN_HARD_RESET: rc = smblib_set_prop_pd_in_hard_reset(chg, val); break; @@ -996,6 +1361,8 @@ static int smb5_usb_set_prop(struct power_supply *psy, else rc = -EINVAL; break; + case POWER_SUPPLY_PROP_TYPE_RECHECK: + rc = smblib_set_prop_type_recheck(chg, val); case POWER_SUPPLY_PROP_VOLTAGE_MAX_LIMIT: smblib_set_prop_usb_voltage_max_limit(chg, val); break; @@ -1026,6 +1393,7 @@ static int smb5_usb_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX_LIMIT: case POWER_SUPPLY_PROP_ADAPTER_CC_MODE: case POWER_SUPPLY_PROP_APSD_RERUN: + case POWER_SUPPLY_PROP_PD_AUTHENTICATION: return 1; default: break; @@ -1049,10 +1417,11 @@ static int smb5_init_usb_psy(struct smb5 *chip) struct power_supply_config usb_cfg = {}; struct smb_charger *chg = &chip->chg; + chg->usb_psy_desc = usb_psy_desc; usb_cfg.drv_data = chip; usb_cfg.of_node = chg->dev->of_node; chg->usb_psy = devm_power_supply_register(chg->dev, - &usb_psy_desc, + &chg->usb_psy_desc, &usb_cfg); if (IS_ERR(chg->usb_psy)) { pr_err("Couldn't register USB power supply\n"); @@ -1085,6 +1454,11 @@ static int smb5_usb_port_get_prop(struct power_supply *psy, val->intval = POWER_SUPPLY_TYPE_USB; break; case POWER_SUPPLY_PROP_ONLINE: + if (chg->report_usb_absent) { + val->intval = 0; + break; + } + rc = smblib_get_prop_usb_online(chg, val); if (!val->intval) break; @@ -1451,15 +1825,15 @@ static int smb5_dc_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_VOLTAGE_MAX: rc = smblib_get_prop_dc_voltage_max(chg, val); break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + smb5_get_prop_input_voltage_regulation(chg, val); + break; case POWER_SUPPLY_PROP_REAL_TYPE: val->intval = POWER_SUPPLY_TYPE_WIPOWER; break; case POWER_SUPPLY_PROP_DC_RESET: val->intval = 0; break; - case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: - rc = smblib_get_prop_voltage_wls_output(chg, val); - break; default: return -EINVAL; } @@ -1504,6 +1878,8 @@ static int smb5_dc_prop_is_writeable(struct power_supply *psy, { switch (psp) { case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + case POWER_SUPPLY_PROP_INPUT_SUSPEND: + case POWER_SUPPLY_PROP_CURRENT_MAX: return 1; default: break; @@ -1533,18 +1909,193 @@ static int smb5_init_dc_psy(struct smb5 *chip) &dc_psy_desc, &dc_cfg); if (IS_ERR(chg->dc_psy)) { - pr_err("Couldn't register USB power supply\n"); + pr_err("Couldn't register dc power supply\n"); return PTR_ERR(chg->dc_psy); } return 0; } +static int smb5_get_prop_wireless_signal(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + + chg->idtp_psy = power_supply_get_by_name("idt"); + if (chg->idtp_psy) + chg->wls_chip_psy = chg->idtp_psy; + + if (chg->wls_chip_psy) + rc = power_supply_get_property(chg->wls_chip_psy, + POWER_SUPPLY_PROP_SIGNAL_STRENGTH, val); + + return rc; +} + +static int smb5_set_prop_input_voltage_regulation(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc; + + chg->idtp_psy = power_supply_get_by_name("idt"); + if (chg->idtp_psy) + chg->wls_chip_psy = chg->idtp_psy; + + if (chg->wls_chip_psy) + rc = power_supply_set_property(chg->wls_chip_psy, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, val); + + return rc; +} + +static int smb5_get_prop_wirless_type(struct smb_charger *chg, + union power_supply_propval *val) +{ + chg->idtp_psy = power_supply_get_by_name("idt"); + if (chg->idtp_psy) + power_supply_get_property(chg->idtp_psy, + POWER_SUPPLY_PROP_TX_ADAPTER, val); + + return 1; +} + +/************************* + * WIRELESS PSY REGISTRATION * + *************************/ + +static enum power_supply_property smb5_wireless_props[] = { + POWER_SUPPLY_PROP_WIRELESS_VERSION, + POWER_SUPPLY_PROP_SIGNAL_STRENGTH, + POWER_SUPPLY_PROP_WIRELESS_WAKELOCK, + POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, + POWER_SUPPLY_PROP_WIRELESS_CP_EN, + POWER_SUPPLY_PROP_WIRELESS_POWER_GOOD_EN, + POWER_SUPPLY_PROP_TX_ADAPTER, +}; + +static int smb5_wireless_set_prop(struct power_supply *psy, + enum power_supply_property psp, + const union power_supply_propval *val) +{ + struct smb5 *chip = power_supply_get_drvdata(psy); + struct smb_charger *chg = &chip->chg; + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_WIRELESS_VERSION: + dev_info(chg->dev, "set version=%d\n", val->intval); + break; + case POWER_SUPPLY_PROP_WIRELESS_WAKELOCK: + rc = smblib_set_prop_wireless_wakelock(chg, val); + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + smb5_set_prop_input_voltage_regulation(chg, val); + break; + case POWER_SUPPLY_PROP_WIRELESS_CP_EN: + smblib_set_wirless_cp_enable(chg, val); + break; + case POWER_SUPPLY_PROP_WIRELESS_POWER_GOOD_EN: + smblib_set_wirless_power_good_enable(chg, val); + break; + default: + return -EINVAL; + } + + return rc; +} + +static int smb5_wireless_get_prop(struct power_supply *psy, + enum power_supply_property psp, + union power_supply_propval *val) +{ + struct smb5 *chip = power_supply_get_drvdata(psy); + struct smb_charger *chg = &chip->chg; + int rc = 0; + + switch (psp) { + case POWER_SUPPLY_PROP_WIRELESS_VERSION: + rc = smblib_get_prop_wireless_version(chg, val); + break; + case POWER_SUPPLY_PROP_SIGNAL_STRENGTH: + smb5_get_prop_wireless_signal(chg, val); + break; + case POWER_SUPPLY_PROP_WIRELESS_WAKELOCK: + val->intval = 1; + break; + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + smb5_get_prop_input_voltage_regulation(chg, val); + break; + case POWER_SUPPLY_PROP_WIRELESS_CP_EN: + val->intval = chg->flag_dc_present; + break; + case POWER_SUPPLY_PROP_WIRELESS_POWER_GOOD_EN: + val->intval = chg->power_good_en; + break; + case POWER_SUPPLY_PROP_TX_ADAPTER: + smb5_get_prop_wirless_type(chg, val); + break; + default: + return -EINVAL; + } + if (rc < 0) { + pr_debug("Couldn't get prop %d rc = %d\n", psp, rc); + return -ENODATA; + } + return 0; +} + +static int smb5_wireless_prop_is_writeable(struct power_supply *psy, + enum power_supply_property psp) +{ + switch (psp) { + case POWER_SUPPLY_PROP_WIRELESS_VERSION: + case POWER_SUPPLY_PROP_WIRELESS_WAKELOCK: + case POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION: + case POWER_SUPPLY_PROP_WIRELESS_CP_EN: + case POWER_SUPPLY_PROP_WIRELESS_POWER_GOOD_EN: + return 1; + default: + break; + } + + return 0; +} + +static const struct power_supply_desc wireless_psy_desc = { + .name = "wireless", + .type = POWER_SUPPLY_TYPE_WIRELESS, + .properties = smb5_wireless_props, + .num_properties = ARRAY_SIZE(smb5_wireless_props), + .get_property = smb5_wireless_get_prop, + .set_property = smb5_wireless_set_prop, + .property_is_writeable = smb5_wireless_prop_is_writeable, +}; + +static int smb5_init_wireless_psy(struct smb5 *chip) +{ + struct power_supply_config wireless_cfg = {}; + struct smb_charger *chg = &chip->chg; + + wireless_cfg.drv_data = chip; + wireless_cfg.of_node = chg->dev->of_node; + chg->wireless_psy = power_supply_register(chg->dev, + &wireless_psy_desc, + &wireless_cfg); + if (IS_ERR(chg->wireless_psy)) { + pr_err("Couldn't register wireless power supply\n"); + return PTR_ERR(chg->wireless_psy); + } + + return 0; +} + /************************* * BATT PSY REGISTRATION * *************************/ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_INPUT_SUSPEND, + POWER_SUPPLY_PROP_LIQUID_DETECTION, + POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED, POWER_SUPPLY_PROP_STATUS, POWER_SUPPLY_PROP_HEALTH, POWER_SUPPLY_PROP_PRESENT, @@ -1579,6 +2130,7 @@ static enum power_supply_property smb5_batt_props[] = { POWER_SUPPLY_PROP_CHARGE_FULL, POWER_SUPPLY_PROP_FORCE_RECHARGE, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, + POWER_SUPPLY_PROP_DC_THERMAL_LEVELS, }; #define DEBUG_ACCESSORY_TEMP_DECIDEGC 250 @@ -1614,6 +2166,9 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT_MAX: rc = smblib_get_prop_system_temp_level_max(chg, val); break; + case POWER_SUPPLY_PROP_DC_THERMAL_LEVELS: + rc = smblib_get_prop_dc_temp_level(chg, val); + break; case POWER_SUPPLY_PROP_CHARGER_TEMP: rc = smblib_get_prop_charger_temp(chg, val); break; @@ -1644,8 +2199,9 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CURRENT_NOW: rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CURRENT_NOW, val); - if (!rc) - val->intval *= (-1); + /* we keep ibat to real value for 6485 or factory test */ + /* if (!rc) + val->intval *= (-1); */ break; case POWER_SUPPLY_PROP_CURRENT_QNOVO: val->intval = get_client_vote_locked(chg->fcc_votable, @@ -1669,7 +2225,7 @@ static int smb5_batt_get_prop(struct power_supply *psy, POWER_SUPPLY_PROP_TEMP, val); break; case POWER_SUPPLY_PROP_TECHNOLOGY: - val->intval = POWER_SUPPLY_TECHNOLOGY_LION; + val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO; break; case POWER_SUPPLY_PROP_CHARGE_DONE: rc = smblib_get_prop_batt_charge_done(chg, val); @@ -1718,6 +2274,15 @@ static int smb5_batt_get_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: val->intval = chg->fcc_stepper_enable; break; + case POWER_SUPPLY_PROP_LIQUID_DETECTION: + if (chg->support_liquid == true) + rc = smblib_get_prop_liquid_status(chg, val); + else + val->intval = 0; + break; + case POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED: + val->intval = chg->dynamic_fv_enabled; + break; default: pr_err("batt power supply prop %d not supported\n", psp); return -EINVAL; @@ -1748,6 +2313,10 @@ static int smb5_batt_set_prop(struct power_supply *psy, case POWER_SUPPLY_PROP_CHARGE_CONTROL_LIMIT: rc = smblib_set_prop_system_temp_level(chg, val); break; + case POWER_SUPPLY_PROP_DC_THERMAL_LEVELS: + if (chg->support_wireless) + rc = smblib_set_prop_dc_temp_level(chg, val); + break; case POWER_SUPPLY_PROP_CAPACITY: rc = smblib_set_prop_batt_capacity(chg, val); break; @@ -1816,6 +2385,13 @@ static int smb5_batt_set_prop(struct power_supply *psy, vote(chg->chg_disable_votable, FORCE_RECHARGE_VOTER, false, 0); break; + case POWER_SUPPLY_PROP_LIQUID_DETECTION: + chg->lpd_status = val->intval; + power_supply_changed(chg->batt_psy); + break; + case POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED: + chg->dynamic_fv_enabled = !!val->intval; + break; case POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE: chg->fcc_stepper_enable = val->intval; break; @@ -1840,6 +2416,9 @@ static int smb5_batt_prop_is_writeable(struct power_supply *psy, case POWER_SUPPLY_PROP_INPUT_CURRENT_LIMITED: case POWER_SUPPLY_PROP_STEP_CHARGING_ENABLED: case POWER_SUPPLY_PROP_DIE_HEALTH: + case POWER_SUPPLY_PROP_DC_THERMAL_LEVELS: + case POWER_SUPPLY_PROP_LIQUID_DETECTION: + case POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED: return 1; default: break; @@ -2542,6 +3121,12 @@ static int smb5_init_hw(struct smb5 *chip) &chg->default_aicl_cont_threshold_mv); chg->aicl_cont_threshold_mv = chg->default_aicl_cont_threshold_mv; + if (chip->dt.dc_icl_ua < 0) { + smblib_get_charge_param(chg, &chg->param.dc_icl, + &chip->dt.dc_icl_ua); + chip->dt.dc_icl_ua = smblib_change_psns_to_curr(chg, chip->dt.dc_icl_ua); + } + if (chg->charger_temp_max == -EINVAL) { rc = smblib_get_thermal_threshold(chg, DIE_REG_H_THRESHOLD_MSB_REG, @@ -2689,6 +3274,19 @@ static int smb5_init_hw(struct smb5 *chip) if (rc < 0) return rc; + /* set dc icl by default voter */ + vote(chg->dc_icl_votable, + DCIN_ADAPTER_VOTER, true, chip->dt.dc_icl_ua); + + /* Disable DC Input missing poller function */ + rc = smblib_masked_write(chg, DCIN_LOAD_CFG_REG, + INPUT_MISS_POLL_EN_BIT, 0); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't disable DC Input missing poller rc=%d\n", rc); + return rc; + } + /* * AICL configuration: enable aicl and aicl rerun and based on DT * configuration enable/disable ADB based AICL and Suspend on collapse. @@ -2716,6 +3314,12 @@ static int smb5_init_hw(struct smb5 *chip) return rc; } + rc = smblib_masked_write(chg, DCIN_BASE + 0x65 , BIT(5), 0); + if (rc < 0) { + dev_err(chg->dev, + "Couldn't configure IMP rc=%d\n", rc); + } + /* enable the charging path */ rc = vote(chg->chg_disable_votable, DEFAULT_VOTER, false, 0); if (rc < 0) { @@ -2752,7 +3356,10 @@ static int smb5_init_hw(struct smb5 *chip) rc = smblib_masked_write(chg, WD_CFG_REG, WATCHDOG_TRIGGER_AFP_EN_BIT | WDOG_TIMER_EN_ON_PLUGIN_BIT | - BARK_WDOG_INT_EN_BIT, val); + BARK_WDOG_INT_EN_BIT | + WDOG_TIMER_EN_BIT, + WDOG_TIMER_EN_ON_PLUGIN_BIT | + BARK_WDOG_INT_EN_BIT); if (rc < 0) { pr_err("Couldn't configue WD config rc=%d\n", rc); return rc; @@ -2921,6 +3528,13 @@ static int smb5_init_hw(struct smb5 *chip) } } + rc = smblib_masked_write(chg, TYPE_C_DEBUG_ACC_SNK_CFG, 0x1F, 0x07); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure TYPE_C_DEBUG_ACC_SNK_CFG rc=%d\n", + rc); + return rc; + } + if (chg->smb_pull_up != -EINVAL) { rc = smb5_configure_internal_pull(chg, SMB_THERM, get_valid_pullup(chg->smb_pull_up)); @@ -2980,10 +3594,18 @@ static int smb5_determine_initial_status(struct smb5 *chip) } chg->early_usb_attach = val.intval; + rc = smblib_get_prop_dc_present(chg, &val); + if (rc < 0) { + pr_err("Couldn't get usb present rc=%d\n", rc); + return rc; + } + chg->early_dc_attach = val.intval; + if (chg->bms_psy) smblib_suspend_on_debug_battery(chg); usb_plugin_irq_handler(0, &irq_data); + dc_plugin_irq_handler(0, &irq_data); typec_attach_detach_irq_handler(0, &irq_data); typec_state_change_irq_handler(0, &irq_data); usb_source_change_irq_handler(0, &irq_data); @@ -3064,7 +3686,6 @@ static struct smb_irq_info smb5_irqs[] = { [BAT_TEMP_IRQ] = { .name = "bat-temp", .handler = batt_temp_changed_irq_handler, - .wake = true, }, [ALL_CHNL_CONV_DONE_IRQ] = { .name = "all-chnl-conv-done", @@ -3134,7 +3755,7 @@ static struct smb_irq_info smb5_irqs[] = { }, [DCIN_UV_IRQ] = { .name = "dcin-uv", - .handler = dcin_uv_irq_handler, + .handler = dcin_uv_handler, .wake = true, }, [DCIN_OV_IRQ] = { @@ -3161,7 +3782,6 @@ static struct smb_irq_info smb5_irqs[] = { [TYPEC_OR_RID_DETECTION_CHANGE_IRQ] = { .name = "typec-or-rid-detect-change", .handler = typec_or_rid_detection_change_irq_handler, - .wake = true, }, [TYPEC_VPD_DETECT_IRQ] = { .name = "typec-vpd-detect", @@ -3339,6 +3959,12 @@ static int smb5_request_interrupts(struct smb5 *chip) } } + /*enable batt_temp irq when plugin usb poweron charging*/ + if (chg->irq_info[BAT_TEMP_IRQ].irq && (chg->early_usb_attach || chg->early_dc_attach)) { + enable_irq_wake(chg->irq_info[BAT_TEMP_IRQ].irq); + chg->batt_temp_irq_enabled = true; + } + vote(chg->limited_irq_disable_votable, CHARGER_TYPE_VOTER, true, 0); vote(chg->hdc_irq_disable_votable, CHARGER_TYPE_VOTER, true, 0); @@ -3501,6 +4127,9 @@ static int smb5_probe(struct platform_device *pdev) chg->connector_health = -EINVAL; chg->otg_present = false; chg->main_fcc_max = -EINVAL; + chg->fake_dc_on = false; + chg->support_liquid = false; + chg->init_once = false; chg->regmap = dev_get_regmap(chg->dev->parent, NULL); if (!chg->regmap) { @@ -3536,6 +4165,8 @@ static int smb5_probe(struct platform_device *pdev) /* set driver data before resources request it */ platform_set_drvdata(pdev, chip); + device_init_wakeup(chg->dev, true); + /* extcon registration */ chg->extcon = devm_extcon_dev_allocate(chg->dev, smblib_extcon_cable); if (IS_ERR(chg->extcon)) { @@ -3649,6 +4280,13 @@ static int smb5_probe(struct platform_device *pdev) goto cleanup; } + rc = smb5_init_wireless_psy(chip); + if (rc < 0) { + pr_err("Couldn't initialize wireless psy rc=%d\n", rc); + goto cleanup; + } + + rc = smb5_request_interrupts(chip); if (rc < 0) { pr_err("Couldn't request interrupts rc=%d\n", rc); @@ -3669,9 +4307,8 @@ static int smb5_probe(struct platform_device *pdev) goto free_irq; } - device_init_wakeup(chg->dev, true); - pr_info("QPNP SMB5 probed successfully\n"); + smblib_support_liquid_feature(chg); return rc; diff --git a/drivers/power/supply/qcom/smb1390-charger.c b/drivers/power/supply/qcom/smb1390-charger.c index a97011142075..1ab82b636121 100644 --- a/drivers/power/supply/qcom/smb1390-charger.c +++ b/drivers/power/supply/qcom/smb1390-charger.c @@ -1,4 +1,5 @@ /* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -87,6 +88,7 @@ #define ILIM_VOTER "ILIM_VOTER" #define FCC_VOTER "FCC_VOTER" #define ICL_VOTER "ICL_VOTER" +#define ICL_CHANGE_VOTER "ICL_CHANGE_VOTER" #define TAPER_END_VOTER "TAPER_END_VOTER" #define WIRELESS_VOTER "WIRELESS_VOTER" #define SRC_VOTER "SRC_VOTER" @@ -139,6 +141,7 @@ struct smb1390 { int irqs[NUM_IRQS]; bool status_change_running; bool taper_work_running; + bool taper_early_trigger; struct smb1390_iio iio; int irq_status; int taper_entry_fv; @@ -343,6 +346,20 @@ static ssize_t stat2_show(struct class *c, struct class_attribute *attr, } static CLASS_ATTR_RO(stat2); +static ssize_t model_name_show(struct class *c, struct class_attribute *attr, + char *buf) +{ + struct smb1390 *chip = container_of(c, struct smb1390, cp_class); + int rc, val; + + rc = smb1390_read(chip, CORE_STATUS1_REG, &val); + if (rc < 0) + return snprintf(buf, PAGE_SIZE, "%s\n", "unknown"); + else + return snprintf(buf, PAGE_SIZE, "%s\n", "smb1390"); +} +static CLASS_ATTR_RO(model_name); + static ssize_t enable_show(struct class *c, struct class_attribute *attr, char *buf) { @@ -469,6 +486,7 @@ static struct attribute *cp_class_attrs[] = { &class_attr_toggle_switcher.attr, &class_attr_die_temp.attr, &class_attr_isns.attr, + &class_attr_model_name.attr, NULL, }; ATTRIBUTE_GROUPS(cp_class); @@ -519,7 +537,7 @@ static int smb1390_ilim_vote_cb(struct votable *votable, void *data, } /* ILIM less than 1A is not accurate; disable charging */ - if (ilim_uA < 1000000) { + if (ilim_uA < 900000) { pr_debug("ILIM %duA is too low to allow charging\n", ilim_uA); vote(chip->disable_votable, ILIM_VOTER, true, 0); } else { @@ -575,12 +593,17 @@ static int smb1390_notifier_cb(struct notifier_block *nb, return NOTIFY_OK; } + +#define TAPER_CAPACITY_THR 55 +#define TAPER_CAPCITY_DELTA 1 +#define BATT_COOL_THR 220 static void smb1390_status_change_work(struct work_struct *work) { struct smb1390 *chip = container_of(work, struct smb1390, status_change_work); union power_supply_propval pval = {0, }; int max_fcc_ma, rc; + int capacity, batt_temp, charge_type; if (!is_psy_voter_available(chip)) goto out; @@ -612,6 +635,7 @@ static void smb1390_status_change_work(struct work_struct *work) */ if (pval.intval == POWER_SUPPLY_CP_WIRELESS) { vote(chip->ilim_votable, ICL_VOTER, false, 0); + vote(chip->ilim_votable, ICL_CHANGE_VOTER, false, 0); rc = power_supply_get_property(chip->dc_psy, POWER_SUPPLY_PROP_CURRENT_MAX, &pval); if (rc < 0) @@ -650,6 +674,49 @@ static void smb1390_status_change_work(struct work_struct *work) if (get_effective_result(chip->disable_votable)) goto out; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &pval); + if (rc < 0) { + pr_err("Couldn't get batt capacity rc=%d\n", rc); + goto out; + } + capacity = pval.intval; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_TEMP, &pval); + if (rc < 0) { + pr_err("Couldn't get batt temp rc=%d\n", rc); + goto out; + } + batt_temp = pval.intval; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); + if (rc < 0) { + pr_err("Couldn't get charge type rc=%d\n", rc); + goto out; + } + charge_type = pval.intval; + + pr_info("capacity:%d, batt_temp:%d, charge_type:%d\n", + capacity, batt_temp, charge_type); + + if ((capacity < TAPER_CAPACITY_THR) + && (batt_temp >= BATT_COOL_THR) + && (charge_type == POWER_SUPPLY_CHARGE_TYPE_FAST) + && chip->taper_early_trigger) { + if (is_client_vote_enabled(chip->fcc_votable, + CP_VOTER)) { + /* reset cp_voter here */ + vote(chip->fcc_votable, CP_VOTER, false, 0); + /* input current is always half the charge current */ + vote(chip->ilim_votable, FCC_VOTER, true, + get_effective_result(chip->fcc_votable) / 2); + chip->taper_early_trigger = false; + } + } + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); if (rc < 0) { @@ -673,6 +740,7 @@ static void smb1390_status_change_work(struct work_struct *work) BATT_PROFILE_VOTER); vote(chip->fcc_votable, CP_VOTER, max_fcc_ma > 0 ? true : false, max_fcc_ma); + chip->taper_early_trigger = false; vote(chip->disable_votable, SOC_LEVEL_VOTER, true, 0); } @@ -686,12 +754,24 @@ static void smb1390_taper_work(struct work_struct *work) struct smb1390 *chip = container_of(work, struct smb1390, taper_work); union power_supply_propval pval = {0, }; int rc, fcc_uA; + int capacity; if (!is_psy_voter_available(chip)) goto out; chip->taper_entry_fv = get_effective_result(chip->fv_votable); while (true) { + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_CAPACITY, &pval); + if (rc < 0) { + pr_err("Couldn't get batt capacity rc=%d\n", rc); + goto out; + } + capacity = pval.intval; + if ((capacity < (TAPER_CAPACITY_THR - TAPER_CAPCITY_DELTA)) + && !chip->taper_early_trigger) + chip->taper_early_trigger = true; + rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_CHARGE_TYPE, &pval); if (rc < 0) { @@ -794,7 +874,7 @@ static void smb1390_destroy_votables(struct smb1390 *chip) static int smb1390_init_hw(struct smb1390 *chip) { - int rc; + int rc, val; /* * charge pump is initially disabled; this indirectly votes to allow @@ -820,6 +900,15 @@ static int smb1390_init_hw(struct smb1390 *chip) if (rc < 0) return rc; + rc = smb1390_read(chip, 0x1032, &val); + pr_err("default smb1390 400K 0x1032_REG: 0x%x\n", val); + + rc = smb1390_masked_write(chip, 0x1032, 0x0F, 0x07); + rc = smb1390_read(chip, 0x1032, &val); + pr_err("modify smb1390 800K 0x1032_REG: 0x%x\n", val); + + if (rc < 0) + return rc; return 0; } diff --git a/drivers/power/supply/qcom/smb5-lib.c b/drivers/power/supply/qcom/smb5-lib.c index af931928e4b6..8d1407bb8c28 100644 --- a/drivers/power/supply/qcom/smb5-lib.c +++ b/drivers/power/supply/qcom/smb5-lib.c @@ -1,4 +1,5 @@ /* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -47,8 +48,14 @@ || typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) \ && (!chg->typec_legacy || chg->typec_legacy_use_rp_icl)) +static bool off_charge_flag; + +bool smblib_rsbux_low(struct smb_charger *chg, int r_thr); +static int smblib_get_prop_typec_mode(struct smb_charger *chg); + static void update_sw_icl_max(struct smb_charger *chg, int pst); static int smblib_get_prop_typec_mode(struct smb_charger *chg); +static int smblib_get_prop_dfp_mode(struct smb_charger *chg); int smblib_read(struct smb_charger *chg, u16 addr, u8 *val) { @@ -106,6 +113,23 @@ int smblib_get_iio_channel(struct smb_charger *chg, const char *propname, return rc; } +static void smblib_wireless_set_enable(struct smb_charger *chg, int enable) +{ + int rc = 0; + union power_supply_propval val = {0, }; + + chg->idtp_psy = power_supply_get_by_name("idt"); + if (chg->idtp_psy) + { + val.intval = enable; + rc = power_supply_set_property(chg->idtp_psy, POWER_SUPPLY_PROP_PIN_ENABLED, &val); + if (rc < 0) { + smblib_err(chg, "Could not set charger control limit =%d\n", rc); + return; + } + } +} + #define DIV_FACTOR_MICRO_V_I 1 #define DIV_FACTOR_MILI_V_I 1000 #define DIV_FACTOR_DECIDEGC 100 @@ -1046,16 +1070,20 @@ static const struct apsd_result *smblib_update_usb_type(struct smb_charger *chg) /* if PD is active, APSD is disabled so won't have a valid result */ if (chg->pd_active) { chg->real_charger_type = POWER_SUPPLY_TYPE_USB_PD; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_PD; } else if (chg->qc3p5_detected) { chg->real_charger_type = POWER_SUPPLY_TYPE_USB_HVDCP_3P5; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_HVDCP_3P5; } else { /* * Update real charger type only if its not FLOAT * detected as as SDP */ if (!(apsd_result->pst == POWER_SUPPLY_TYPE_USB_FLOAT && - chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) + chg->real_charger_type == POWER_SUPPLY_TYPE_USB)) { chg->real_charger_type = apsd_result->pst; + chg->usb_psy_desc.type = apsd_result->pst; + } } smblib_dbg(chg, PR_MISC, "APSD=%s PD=%d QC3P5=%d\n", @@ -1201,6 +1229,7 @@ static void smblib_uusb_removal(struct smb_charger *chg) del_timer_sync(&chg->apsd_timer); chg->apsd_ext_timeout = false; + chg->report_usb_absent = false; /* write back the default FLOAT charger configuration */ rc = smblib_masked_write(chg, USBIN_OPTIONS_2_CFG_REG, @@ -1271,6 +1300,7 @@ void smblib_suspend_on_debug_battery(struct smb_charger *chg) int smblib_rerun_apsd_if_required(struct smb_charger *chg) { union power_supply_propval val; + const struct apsd_result *apsd_result; int rc; rc = smblib_get_prop_usb_present(chg, &val); @@ -1279,16 +1309,32 @@ int smblib_rerun_apsd_if_required(struct smb_charger *chg) return rc; } - if (!val.intval) + if (!val.intval || chg->fake_usb_insertion) return 0; + /* rc = smblib_request_dpdm(chg, true); if (rc < 0) smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); + */ chg->uusb_apsd_rerun_done = true; - smblib_rerun_apsd(chg); + if (!off_charge_flag) { + rc = smblib_request_dpdm(chg, true); + if (rc < 0) + smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); + smblib_rerun_apsd(chg); + } else { + apsd_result = smblib_update_usb_type(chg); + /* if apsd result is SDP and off-charge mode, no need rerun apsd */ + if (!(apsd_result->bit & SDP_CHARGER_BIT)) { + rc = smblib_request_dpdm(chg, true); + if (rc < 0) + smblib_err(chg, "Couldn't to enable DPDM rc=%d\n", rc); + smblib_rerun_apsd(chg); + } + } return 0; } @@ -1382,6 +1428,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) /* configure current */ if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB + && (icl_ua <= USBIN_500MA) && (chg->typec_legacy || chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_DEFAULT || chg->connector_type == POWER_SUPPLY_CONNECTOR_MICRO_USB)) { @@ -1396,7 +1443,7 @@ int smblib_set_icl_current(struct smb_charger *chg, int icl_ua) * current limit is 500mA or below for better accuracy; in case * of error, proceed to use USB high-current mode. */ - if (icl_ua <= USBIN_500MA) { + if (icl_ua < USBIN_100MA) { rc = set_sdp_current(chg, icl_ua); if (rc >= 0) goto unsuspend; @@ -1612,6 +1659,44 @@ static int smblib_dc_suspend_vote_callback(struct votable *votable, void *data, return smblib_set_dc_suspend(chg, (bool)suspend); } +static int smblib_dc_icl_vote_callback(struct votable *votable, void *data, + int icl_ua, const char *client) +{ + struct smb_charger *chg = data; + int rc = 0; + bool suspend; + int Vpsns; + + if (icl_ua < 0) { + smblib_dbg(chg, PR_MISC, "No Voter hence suspending\n"); + icl_ua = 0; + } + + suspend = (icl_ua <= USBIN_25MA); + if (suspend) + goto suspend; + + Vpsns = (icl_ua/PSNS_CURRENT_SAMPLE_RATE) * PSNS_CURRENT_SAMPLE_RESIS; + if (chg->dc_temp_level == 13 || chg->dc_temp_level == 9) + Vpsns += PSNS_COMP_UV_FOR_HIGH_THERMAL; + + rc = smblib_set_charge_param(chg, &chg->param.dc_icl, Vpsns); + if (rc < 0) { + smblib_err(chg, "Couldn't set DC input current limit rc=%d\n", + rc); + return rc; + } + +suspend: + rc = vote(chg->dc_suspend_votable, USER_VOTER, suspend, 0); + if (rc < 0) { + smblib_err(chg, "Couldn't vote to %s DC rc=%d\n", + suspend ? "suspend" : "resume", rc); + return rc; + } + return rc; +} + static int smblib_awake_vote_callback(struct votable *votable, void *data, int awake, const char *client) { @@ -1856,7 +1941,7 @@ int smblib_get_prop_input_suspend(struct smb_charger *chg, { val->intval = (get_client_vote(chg->usb_icl_votable, USER_VOTER) == 0) - && get_client_vote(chg->dc_suspend_votable, USER_VOTER); + || get_client_vote(chg->dc_suspend_votable, USER_VOTER); return 0; } @@ -1878,6 +1963,53 @@ int smblib_get_prop_batt_present(struct smb_charger *chg, return rc; } +int smblib_get_prop_batt_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + if (!chg->bms_psy) + return -EINVAL; + + rc = power_supply_get_property(chg->bms_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, val); + return rc; +} + +static void smblib_check_usb_status(struct smb_charger *chg) +{ + int rc; + int usb_present = 0, vbat_uv = 0; + union power_supply_propval pval = {0,}; + + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return; + } + usb_present = pval.intval; + + if (!usb_present) + return; + + rc = smblib_get_prop_batt_voltage_now(chg, &pval); + if (rc < 0) { + pr_err("Couldn't get vbat rc=%d\n", rc); + return; + } + vbat_uv = pval.intval; + + /* + * if battery soc is 0%, vbat is below 3400mV and usb is present in + * normal mode(not power-off charging mode), set online to + * false to notify system to power off. + */ + if ((usb_present == 1) && (!off_charge_flag) + && (vbat_uv <= CUTOFF_VOL_THR)) { + chg->report_usb_absent = true; + power_supply_changed(chg->batt_psy); + } +} + int smblib_get_prop_batt_capacity(struct smb_charger *chg, union power_supply_propval *val) { @@ -1890,9 +2022,72 @@ int smblib_get_prop_batt_capacity(struct smb_charger *chg, rc = smblib_get_prop_from_bms(chg, POWER_SUPPLY_PROP_CAPACITY, val); + if (val->intval == 0) + smblib_check_usb_status(chg); + return rc; } +static bool smblib_wireless_to_usb_charging(struct smb_charger *chg, + bool usb_online, bool dc_online) +{ + if ((usb_online || chg->typec_mode == POWER_SUPPLY_TYPEC_SOURCE_HIGH) + && chg->fake_dc_on) { + /* insert usb when wireless charging, set status + * to charge and charger type to DCP + * insert pd charger when wireless charging, power good irq will + * trigger very qucickly difference with other charger type. + */ + if (!chg->pd_active) { + chg->real_charger_type = POWER_SUPPLY_TYPE_USB_DCP; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_DCP; + } + return true; + } else if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER + && smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE + && chg->power_good_en) { + smblib_dbg(chg, PR_WLS, "otg mode, set charging when pwr on\n"); + return true; + } + else + return false; +} + +static bool smblib_is_jeita_warm_charging(struct smb_charger *chg) +{ + union power_supply_propval pval = {0, }; + bool usb_online, dc_online; + int rc; + + rc = smblib_get_prop_usb_online(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb online property rc=%d\n", + rc); + return rc; + } + usb_online = (bool)pval.intval; + + rc = smblib_get_prop_dc_online(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get dc online property rc=%d\n", + rc); + return rc; + } + dc_online = (bool)pval.intval; + + if (!usb_online && !dc_online) + return false; + + rc = smblib_get_prop_batt_health(chg, &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get batt health rc=%d\n", rc); + + if (POWER_SUPPLY_HEALTH_WARM == pval.intval) + return true; + else + return false; +} + static bool is_charging_paused(struct smb_charger *chg) { int rc; @@ -1965,18 +2160,29 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, stat = stat & BATTERY_CHARGER_STATUS_MASK; if (!usb_online && !dc_online) { - switch (stat) { - case TERMINATE_CHARGE: - case INHIBIT_CHARGE: - val->intval = POWER_SUPPLY_STATUS_FULL; - break; - default: - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; - break; - } + val->intval = POWER_SUPPLY_STATUS_DISCHARGING; return rc; } + rc = smblib_get_prop_batt_health(chg, &pval); + if (rc < 0) + smblib_err(chg, "Couldn't get batt health rc=%d\n", rc); + + if ((get_client_vote_locked(chg->usb_icl_votable, JEITA_VOTER) == 0) || + (get_client_vote_locked(chg->dc_suspend_votable, JEITA_VOTER) == 1)) { + if (pval.intval != POWER_SUPPLY_HEALTH_OVERHEAT + && pval.intval != POWER_SUPPLY_HEALTH_COLD) { + val->intval = POWER_SUPPLY_STATUS_CHARGING; + return 0; + } + } + + if (pval.intval == POWER_SUPPLY_HEALTH_OVERHEAT || + pval.intval == POWER_SUPPLY_HEALTH_COLD) { + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + return 0; + } + switch (stat) { case TRICKLE_CHARGE: case PRE_CHARGE: @@ -1986,17 +2192,45 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, break; case TERMINATE_CHARGE: case INHIBIT_CHARGE: - val->intval = POWER_SUPPLY_STATUS_FULL; + if (POWER_SUPPLY_HEALTH_WARM == pval.intval + || POWER_SUPPLY_HEALTH_OVERHEAT == pval.intval) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else { + val->intval = POWER_SUPPLY_STATUS_FULL; + chg->last_batt_stat = val->intval; + } break; case DISABLE_CHARGE: case PAUSE_CHARGE: - val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; + if (smblib_is_jeita_warm_charging(chg) + || smblib_wireless_to_usb_charging(chg, usb_online, dc_online)) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + else + val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; break; default: val->intval = POWER_SUPPLY_STATUS_UNKNOWN; break; } + if (!usb_online && chg->typec_mode != POWER_SUPPLY_TYPEC_SOURCE_HIGH + && dc_online && chg->fake_dc_on) { + /* + * fix insert wireless charger the logo will show twice. + * Also include wireless swith to pd charger, "wireless charger stop" issue. + */ + if (val->intval == POWER_SUPPLY_STATUS_CHARGING) + chg->fake_dc_on = 0; + else if (chg->last_batt_stat == POWER_SUPPLY_STATUS_FULL && + val->intval != POWER_SUPPLY_STATUS_CHARGING) { + val->intval = POWER_SUPPLY_STATUS_FULL; + chg->last_batt_stat = val->intval; + } + else if (val->intval != POWER_SUPPLY_STATUS_FULL) + val->intval = POWER_SUPPLY_STATUS_CHARGING; + return 0; + } + if (is_charging_paused(chg)) { val->intval = POWER_SUPPLY_STATUS_CHARGING; return 0; @@ -2012,15 +2246,18 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, return 0; } - if (val->intval != POWER_SUPPLY_STATUS_CHARGING) + if (val->intval != POWER_SUPPLY_STATUS_CHARGING + || pval.intval == POWER_SUPPLY_HEALTH_WARM) return 0; if (!usb_online && dc_online && chg->fake_batt_status == POWER_SUPPLY_STATUS_FULL) { val->intval = POWER_SUPPLY_STATUS_FULL; + chg->last_batt_stat = val->intval; return 0; } +/* rc = smblib_read(chg, BATTERY_CHARGER_STATUS_5_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read BATTERY_CHARGER_STATUS_2 rc=%d\n", @@ -2033,6 +2270,7 @@ int smblib_get_prop_batt_status(struct smb_charger *chg, if (!stat) val->intval = POWER_SUPPLY_STATUS_NOT_CHARGING; +*/ return 0; } @@ -2093,7 +2331,7 @@ int smblib_get_prop_batt_health(struct smb_charger *chg, * If Vbatt is within 40mV above Vfloat, then don't * treat it as overvoltage. */ - effective_fv_uv = get_effective_result(chg->fv_votable); + effective_fv_uv = get_effective_result_locked(chg->fv_votable); if (pval.intval >= effective_fv_uv + 40000) { val->intval = POWER_SUPPLY_HEALTH_OVERVOLTAGE; smblib_err(chg, "battery over-voltage vbat_fg = %duV, fv = %duV\n", @@ -2138,6 +2376,13 @@ int smblib_get_prop_system_temp_level_max(struct smb_charger *chg, return 0; } +int smblib_get_prop_dc_temp_level(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = chg->dc_temp_level; + return 0; +} + int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val) { @@ -2219,9 +2464,63 @@ int smblib_get_prop_batt_charge_done(struct smb_charger *chg, stat = stat & BATTERY_CHARGER_STATUS_MASK; val->intval = (stat == TERMINATE_CHARGE); + + if (val->intval == 1) { + vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0); + vote(chg->awake_votable, DC_AWAKE_VOTER, false, 0); + } + return 0; +} + +int smblib_get_prop_liquid_status(struct smb_charger *chg, + union power_supply_propval *val) +{ + val->intval = 0; + + if (chg->lpd_status) { + val->intval = 1; + } else { + val->intval = 0; + } return 0; } +#define HW_ER_RATIO 2 +#define RF_ADC 1875 + +bool smblib_support_liquid_feature(struct smb_charger *chg) +{ + int hw_version; + int rc, i, data; + int error_value = RF_ADC*HW_ER_RATIO/100; + + if (chg->lpd_enabled == true) { + if (chg->init_once == false) { + rc = smblib_read_iio_channel(chg, chg->iio.hw_version_gpio5, + DIV_FACTOR_MILI_V_I, &hw_version); + if (rc < 0) { + smblib_err(chg, "Couldn't read hw_version_gpio5, rc = %d\n", rc); + return rc; + } else { + smblib_err(chg, "hw_version_gpio5 ADC = %d\n", hw_version); + } + + chg->init_once = true; + + for (i = 0; i < chg->lpd_levels; i++) { + data = (chg->lpd_hwversion[i] * 100) / (100000 + chg->lpd_hwversion[i]); + if (abs(RF_ADC * data / 100 - hw_version) < error_value) { + chg->support_liquid = true; + break; + } + } + } + } + + smblib_err(chg, "support_liquid is %d\n", chg->support_liquid); + return chg->support_liquid; +} + /*********************** * BATTERY PSY SETTERS * ***********************/ @@ -2274,9 +2573,260 @@ int smblib_set_prop_batt_status(struct smb_charger *chg, return 0; } +#define ADAPTER_NONE 0x00 +#define ADAPTER_SDP 0x01 +#define ADAPTER_CDP 0x02 +#define ADAPTER_DCP 0x03 +#define ADAPTER_QC2 0x05 +#define ADAPTER_QC3 0x06 +#define ADAPTER_PD 0x07 +#define ADAPTER_AUTH_FAILED 0x08 +#define ADAPTER_XIAOMI_QC3 0x09 +#define ADAPTER_XIAOMI_PD 0x0a +#define ADAPTER_ZIMI_CAR_POWER 0x0b + +#ifdef CONFIG_THERMAL +static int smblib_dc_therm_charging(struct smb_charger *chg, + int temp_level) +{ + int thermal_icl_ua = 0; + int rc; + union power_supply_propval pval = {0, }; + union power_supply_propval val = {0, }; + + if (!chg->wls_psy) { + chg->wls_psy = power_supply_get_by_name("wireless"); + if (!chg->wls_psy) + return -ENODEV; + } + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_TX_ADAPTER, + &pval); + + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_WIRELESS_VERSION, + &val); + switch (pval.intval) { + case ADAPTER_XIAOMI_QC3: + case ADAPTER_ZIMI_CAR_POWER: + thermal_icl_ua = chg->thermal_mitigation_dc[temp_level]; + break; + case ADAPTER_QC2: + thermal_icl_ua = chg->thermal_mitigation_bpp_qc2[temp_level]; + break; + case ADAPTER_QC3: + if (val.intval == 1)/*is epp*/ + thermal_icl_ua = chg->thermal_mitigation_epp[temp_level]; + else + thermal_icl_ua = chg->thermal_mitigation_bpp_qc3[temp_level]; + break; + case ADAPTER_XIAOMI_PD: + case ADAPTER_PD: + if (val.intval == 1)/*is epp*/ + thermal_icl_ua = chg->thermal_mitigation_epp[temp_level]; + else + thermal_icl_ua = chg->thermal_mitigation_bpp[temp_level]; + break; + case ADAPTER_AUTH_FAILED: + if (val.intval == 1)/*is epp*/ + thermal_icl_ua = chg->thermal_mitigation_epp[temp_level]; + else + thermal_icl_ua = chg->thermal_mitigation_bpp[temp_level]; + break; + case ADAPTER_CDP: + case ADAPTER_DCP: + thermal_icl_ua = chg->thermal_mitigation_bpp[temp_level]; + break; + default: + thermal_icl_ua = chg->thermal_mitigation_bpp[temp_level]; + break; + } + vote(chg->dc_icl_votable, THERMAL_DAEMON_VOTER, true, thermal_icl_ua); + + return rc; +} +#endif +int smblib_set_prop_dc_temp_level(struct smb_charger *chg, + const union power_supply_propval *val) +{ + union power_supply_propval dc_present; + union power_supply_propval batt_temp; + int rc; + + rc = smblib_get_prop_dc_present(chg, &dc_present); + if (rc < 0) { + pr_err("Couldn't get dc present rc=%d\n", rc); + return -EINVAL; + } + + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_TEMP, &batt_temp); + if (rc < 0) { + pr_err("Couldn't get batt temp rc=%d\n", rc); + return -EINVAL; + } + + if (val->intval < 0) + return -EINVAL; + if (chg->dc_thermal_levels <= 0) + return -EINVAL; + if (val->intval > chg->dc_thermal_levels) + return -EINVAL; + chg->dc_temp_level = val->intval; + + if (chg->dc_temp_level == chg->dc_thermal_levels) + return vote(chg->chg_disable_votable, + THERMAL_DAEMON_VOTER, true, 0); + + vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0); + if (chg->dc_temp_level == 0) + return vote(chg->dc_icl_votable, THERMAL_DAEMON_VOTER, false, 0); + +#ifdef CONFIG_THERMAL + smblib_dc_therm_charging(chg, val->intval); +#else + vote(chg->dc_icl_votable, THERMAL_DAEMON_VOTER, true, + chg->thermal_mitigation_dc[chg->dc_temp_level]); + +#endif + return 0; +} + +#ifdef CONFIG_THERMAL +static int smblib_therm_charging(struct smb_charger *chg) +{ + int thermal_icl_ua = 0; + int thermal_fcc_ua = 0; + int rc; + + if (chg->system_temp_level >= MAX_TEMP_LEVEL) + return 0; + + switch (chg->real_charger_type) { + case POWER_SUPPLY_TYPE_USB_HVDCP: + thermal_icl_ua = chg->thermal_mitigation_qc2[chg->system_temp_level]; + break; + case POWER_SUPPLY_TYPE_USB_HVDCP_3: + if (chg->cp_reason == POWER_SUPPLY_CP_HVDCP3) { + if (chg->is_qc_class_a) + thermal_fcc_ua = + chg->thermal_fcc_qc3_cp[chg->system_temp_level]; + else + thermal_fcc_ua = + chg->thermal_fcc_qc3_classb_cp[chg->system_temp_level]; + } else { + thermal_fcc_ua = + chg->thermal_fcc_qc3_normal[chg->system_temp_level]; + } + break; + case POWER_SUPPLY_TYPE_USB_PD: + if (chg->cp_reason == POWER_SUPPLY_CP_PPS) { + thermal_fcc_ua = + chg->thermal_fcc_pps_cp[chg->system_temp_level]; + } else { + if (chg->voltage_min_uv >= PD_MICRO_5V + && chg->voltage_min_uv < PD_MICRO_5P9V) + thermal_icl_ua = + chg->thermal_mitigation_pd_base[chg->system_temp_level]; + else if (chg->voltage_min_uv >= PD_MICRO_5P9V + && chg->voltage_min_uv < PD_MICRO_6P5V) + thermal_icl_ua = + chg->thermal_mitigation_pd_base[chg->system_temp_level] + * PD_6P5V_PERCENT / 100; + else if (chg->voltage_min_uv >= PD_MICRO_6P5V + && chg->voltage_min_uv < PD_MICRO_7P5V) + thermal_icl_ua = + chg->thermal_mitigation_pd_base[chg->system_temp_level] + * PD_7P5V_PERCENT / 100; + else if (chg->voltage_min_uv >= PD_MICRO_7P5V + && chg->voltage_min_uv <= PD_MICRO_8P5V) + thermal_icl_ua = + chg->thermal_mitigation_pd_base[chg->system_temp_level] + * PD_8P5V_PERCENT / 100; + else if (chg->voltage_min_uv >= PD_MICRO_8P5V) + thermal_icl_ua = + chg->thermal_mitigation_pd_base[chg->system_temp_level] + * PD_9V_PERCENT / 100; + else + thermal_icl_ua = + chg->thermal_mitigation_pd_base[chg->system_temp_level]; + } + break; + case POWER_SUPPLY_TYPE_USB_DCP: + default: + thermal_icl_ua = chg->thermal_mitigation_dcp[chg->system_temp_level]; + break; + } + + if (chg->system_temp_level == 0) { + /* if therm_lvl_sel is 0, clear thermal voter */ + rc = vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, false, 0); + if (rc < 0) + pr_err("Couldn't disable USB thermal ICL vote rc=%d\n", + rc); + rc = vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0); + if (rc < 0) + pr_err("Couldn't disable USB thermal ICL vote rc=%d\n", + rc); + } else { + pr_info("thermal_icl_ua is %d, chg->system_temp_level: %d\n", + thermal_icl_ua, chg->system_temp_level); + pr_info("thermal_fcc_ua is %d\n", thermal_fcc_ua); + + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3 + || (chg->cp_reason == POWER_SUPPLY_CP_PPS + && chg->real_charger_type == POWER_SUPPLY_TYPE_USB_PD)) { + if (chg->system_temp_level >= ICL_LIMIT_LEVEL_THR) + thermal_icl_ua = + chg->thermal_mitigation_icl[chg->system_temp_level]; + if (chg->system_temp_level >= ICL_LIMIT_LEVEL_THR) { + rc = vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, + true, thermal_icl_ua); + if (rc < 0) + pr_err("Couldn't enable USB thermal ICL vote rc=%d\n", + rc); + } else { + rc = vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, + false, 0); + if (rc < 0) + pr_err("Couldn't disable USB thermal ICL vote rc=%d\n", + rc); + } + } else { + if (thermal_icl_ua > 0) { + rc = vote(chg->usb_icl_votable, THERMAL_DAEMON_VOTER, true, + thermal_icl_ua); + if (rc < 0) + pr_err("Couldn't enable USB thermal ICL vote rc=%d\n", + rc); + } + } + if (thermal_fcc_ua > 0) { + rc = vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, + thermal_fcc_ua); + if (rc < 0) + pr_err("Couldn't enable USB thermal ICL vote rc=%d\n", + rc); + } + } + + return rc; +} +#endif + int smblib_set_prop_system_temp_level(struct smb_charger *chg, const union power_supply_propval *val) { + int rc; + union power_supply_propval batt_temp = {0, }; + + rc = smblib_get_prop_from_bms(chg, + POWER_SUPPLY_PROP_TEMP, &batt_temp); + if (rc < 0) { + pr_err("Couldn't get batt temp rc=%d\n", rc); + return -EINVAL; + } + if (val->intval < 0) return -EINVAL; @@ -2288,16 +2838,21 @@ int smblib_set_prop_system_temp_level(struct smb_charger *chg, chg->system_temp_level = val->intval; - if (chg->system_temp_level == chg->thermal_levels) + if (chg->system_temp_level >= (chg->thermal_levels - 1)) return vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, true, 0); vote(chg->chg_disable_votable, THERMAL_DAEMON_VOTER, false, 0); + +#ifdef CONFIG_THERMAL + smblib_therm_charging(chg); +#else if (chg->system_temp_level == 0) return vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, false, 0); vote(chg->fcc_votable, THERMAL_DAEMON_VOTER, true, chg->thermal_mitigation[chg->system_temp_level]); +#endif return 0; } @@ -2314,6 +2869,9 @@ int smblib_set_prop_rechg_soc_thresh(struct smb_charger *chg, int rc; u8 new_thr = DIV_ROUND_CLOSEST(val->intval * 255, 100); + if (val->intval == RECHARGE_SOC_THR) + new_thr += 1; + rc = smblib_write(chg, CHARGE_RCHG_SOC_THRESHOLD_CFG_REG, new_thr); if (rc < 0) { @@ -2450,6 +3008,11 @@ static void smblib_hvdcp_adaptive_voltage_change(struct smb_charger *chg) u8 stat; if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) { + if (chg->qc2_unsupported) { + smblib_hvdcp_set_fsw(chg, QC_5V_BIT); + power_supply_changed(chg->usb_main_psy); + return; + } rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, @@ -2477,8 +3040,18 @@ int smblib_dp_dm(struct smb_charger *chg, int val) union power_supply_propval pval; u8 stat; + if (chg->raise_vbus_to_detect) + return rc; + switch (val) { case POWER_SUPPLY_DP_DM_DP_PULSE: + /* + * if hvdcp_opti wrongly send more than 30 dp pulse(11V) to smb5, + * ignore them to allow maxium vbus as 11V, as charge pump do not + * need the vin more than 11V, and protect the device. + */ + if (chg->pulse_cnt > MAX_PLUSE_COUNT_ALLOWED) + return rc; /* * Pre-emptively increment pulse count to enable the setting * of FSW prior to increasing voltage. @@ -2502,6 +3075,14 @@ int smblib_dp_dm(struct smb_charger *chg, int val) smblib_dbg(chg, PR_PARALLEL, "DP_DM_DP_PULSE rc=%d cnt=%d\n", rc, chg->pulse_cnt); + if (chg->is_qc_class_a && chg->sec_cp_present) { + if (chg->pulse_cnt >= HIGH_NUM_PULSE_THR + && !chg->high_vbus_detected) { + vote(chg->usb_icl_votable, QC_A_CP_ICL_MAX_VOTER, true, + HVDCP_CLASS_A_FOR_CP_UA); + chg->high_vbus_detected = true; + } + } break; case POWER_SUPPLY_DP_DM_DM_PULSE: rc = smblib_dm_pulse(chg); @@ -2509,6 +3090,14 @@ int smblib_dp_dm(struct smb_charger *chg, int val) chg->pulse_cnt--; smblib_dbg(chg, PR_PARALLEL, "DP_DM_DM_PULSE rc=%d cnt=%d\n", rc, chg->pulse_cnt); + if (chg->is_qc_class_a && chg->sec_cp_present) { + if (chg->pulse_cnt < HIGH_NUM_PULSE_THR + && chg->high_vbus_detected) { + vote(chg->usb_icl_votable, QC_A_CP_ICL_MAX_VOTER, false, + 0); + chg->high_vbus_detected = false; + } + } break; case POWER_SUPPLY_DP_DM_ICL_DOWN: target_icl_ua = get_effective_result(chg->usb_icl_votable); @@ -2546,6 +3135,11 @@ int smblib_dp_dm(struct smb_charger *chg, int val) pr_err("Failed to force 5V\n"); break; case POWER_SUPPLY_DP_DM_FORCE_9V: + return 0; + + if (chg->qc2_unsupported) + return 0; + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_9V) { smblib_err(chg, "Couldn't set 9V: unsupported\n"); return -EINVAL; @@ -2569,8 +3163,15 @@ int smblib_dp_dm(struct smb_charger *chg, int val) rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT); if (rc < 0) pr_err("Failed to force 9V\n"); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP2_CURRENT_UA); break; case POWER_SUPPLY_DP_DM_FORCE_12V: + return 0; + + if (chg->qc2_unsupported) + return 0; + if (chg->qc2_unsupported_voltage == QC2_NON_COMPLIANT_12V) { smblib_err(chg, "Couldn't set 12V: unsupported\n"); return -EINVAL; @@ -2594,6 +3195,8 @@ int smblib_dp_dm(struct smb_charger *chg, int val) rc = smblib_force_vbus_voltage(chg, FORCE_12V_BIT); if (rc < 0) pr_err("Failed to force 12V\n"); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP2_CURRENT_UA); break; case POWER_SUPPLY_DP_DM_CONFIRMED_HVDCP3P5: chg->qc3p5_detected = true; @@ -2630,6 +3233,36 @@ int smblib_disable_hw_jeita(struct smb_charger *chg, bool disable) return 0; } +int smblib_get_prop_wireless_version(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc; + +/* + if (!chg->idtp_psy) { + chg->idtp_psy = power_supply_get_by_name("idt"); + if (!chg->idtp_psy) + return -EINVAL; + } +*/ + + chg->idtp_psy = power_supply_get_by_name("idt"); + if (chg->idtp_psy) + chg->wls_chip_psy = chg->idtp_psy; + else { + chg->wip_psy = power_supply_get_by_name("rx1618"); + if (chg->wip_psy) + chg->wls_chip_psy = chg->wip_psy; + else + return -EINVAL; + } + + if (chg->wls_chip_psy) + rc = power_supply_get_property(chg->wls_chip_psy, + POWER_SUPPLY_PROP_WIRELESS_VERSION, val); + return rc; +} + static int smblib_set_sw_thermal_regulation(struct smb_charger *chg, bool enable) { @@ -2938,8 +3571,9 @@ int smblib_get_prop_dc_present(struct smb_charger *chg, int smblib_get_prop_dc_online(struct smb_charger *chg, union power_supply_propval *val) { - int rc = 0; + int dc_present, rc = 0; u8 stat; + union power_supply_propval pval = {0, }; if (chg->chg_param.smb_version == PMI632_SUBTYPE) { val->intval = 0; @@ -2951,12 +3585,32 @@ int smblib_get_prop_dc_online(struct smb_charger *chg, return rc; } - if (is_client_vote_enabled(chg->dc_suspend_votable, + if (is_client_vote_enabled_locked(chg->dc_suspend_votable, CHG_TERMINATION_VOTER)) { rc = smblib_get_prop_dc_present(chg, val); return rc; } + rc = smblib_get_prop_dc_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return rc; + } + + dc_present = pval.intval; + + + if (dc_present && + get_client_vote_locked(chg->dc_suspend_votable, JEITA_VOTER) == 1) { + val->intval = true; + return rc; + } + + if (chg->fake_dc_on) { + val->intval = true; + return rc; + } + rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", @@ -2972,10 +3626,25 @@ int smblib_get_prop_dc_online(struct smb_charger *chg, return rc; } +int smblib_set_prop_wireless_wakelock(struct smb_charger *chg, + const union power_supply_propval *val) +{ + if (val->intval) { + vote(chg->awake_votable, DC_AWAKE_VOTER, true, 0); + //schedule_delayed_work(&chg->dc_input_current_work, + // msecs_to_jiffies(100)); //need enable + } else { + vote(chg->awake_votable, DC_AWAKE_VOTER, false, 0); + //cancel_delayed_work_sync(&chg->dc_input_current_work); + } + return 0; +} + int smblib_get_prop_dc_current_max(struct smb_charger *chg, union power_supply_propval *val) { - return smblib_get_charge_param(chg, &chg->param.dc_icl, &val->intval); + val->intval = get_effective_result_locked(chg->dc_icl_votable); + return 0; } int smblib_get_prop_dc_voltage_max(struct smb_charger *chg, @@ -2999,11 +3668,9 @@ int smblib_get_prop_dc_voltage_now(struct smb_charger *chg, rc = power_supply_get_property(chg->wls_psy, POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, val); - if (rc < 0) { - dev_err(chg->dev, "Couldn't get POWER_SUPPLY_PROP_VOLTAGE_REGULATION, rc=%d\n", + if (rc < 0) + dev_err(chg->dev, "Couldn't get POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, rc=%d\n", rc); - return rc; - } return rc; } @@ -3015,7 +3682,10 @@ int smblib_get_prop_dc_voltage_now(struct smb_charger *chg, int smblib_set_prop_dc_current_max(struct smb_charger *chg, const union power_supply_propval *val) { - return smblib_set_charge_param(chg, &chg->param.dc_icl, val->intval); + int rc; + + rc = vote(chg->dc_icl_votable, DCIN_ADAPTER_VOTER, true, val->intval); + return rc; } #define DCIN_AICL_RERUN_DELAY_MS 5000 @@ -3023,6 +3693,7 @@ int smblib_set_prop_voltage_wls_output(struct smb_charger *chg, const union power_supply_propval *val) { int rc; + union power_supply_propval pval = {0, }; if (!chg->wls_psy) { chg->wls_psy = power_supply_get_by_name("wireless"); @@ -3030,6 +3701,29 @@ int smblib_set_prop_voltage_wls_output(struct smb_charger *chg, return -ENODEV; } + rc = power_supply_get_property(chg->wls_psy, + POWER_SUPPLY_PROP_TX_ADAPTER, + &pval); + + if (pval.intval == 9 || pval.intval == 11 || pval.intval == 12) { + if (val->intval >= 9200000 && val->intval < 9500000) + vote(chg->dc_icl_votable, DCIN_LIMIT_VOTER, true, 2000000); + else if (val->intval > 9500000) + vote(chg->dc_icl_votable, DCIN_LIMIT_VOTER, true, 1800000); + else + vote(chg->dc_icl_votable, DCIN_LIMIT_VOTER, false, 0); + } else if (pval.intval == 6) { + if (val->intval > 9000000 && val->intval <= 9500000) + vote(chg->dc_icl_votable, DCIN_LIMIT_VOTER, true, 1100000); + else if (val->intval > 9500000) + vote(chg->dc_icl_votable, DCIN_LIMIT_VOTER, true, 1000000); + else + vote(chg->dc_icl_votable, DCIN_LIMIT_VOTER, false, 0); + } else { + smblib_dbg(chg, PR_WLS, "WLS chg type error %d\n", pval.intval); + return rc; + } + rc = power_supply_set_property(chg->wls_psy, POWER_SUPPLY_PROP_INPUT_VOLTAGE_REGULATION, val); @@ -3128,8 +3822,9 @@ int smblib_get_prop_usb_present(struct smb_charger *chg, int smblib_get_prop_usb_online(struct smb_charger *chg, union power_supply_propval *val) { - int rc = 0; + int usb_present, rc = 0; u8 stat; + union power_supply_propval pval = {0, }; if (get_client_vote_locked(chg->usb_icl_votable, USER_VOTER) == 0) { val->intval = false; @@ -3142,6 +3837,34 @@ int smblib_get_prop_usb_online(struct smb_charger *chg, return rc; } + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return rc; + } + + usb_present = pval.intval; + + if (usb_present && chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { + val->intval = true; + return rc; + } + + if (usb_present && + get_client_vote_locked(chg->usb_icl_votable, JEITA_VOTER) == 0) { + val->intval = true; + return rc; + } + + if (usb_present && chg->power_good_en) { + /* show online when insert usb in wireless charging */ + if (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK) + val->intval = false; + else + val->intval = true; + return rc; + } + rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", @@ -3328,6 +4051,23 @@ int smblib_get_prop_vph_voltage_now(struct smb_charger *chg, return 0; } +int smblib_get_usb_in_voltage_now(struct smb_charger *chg, + union power_supply_propval *val) +{ + int rc, ret = 0; + + if (chg->iio.usbin_v_chan) { + rc = iio_read_channel_processed(chg->iio.usbin_v_chan, + &val->intval); + if (rc < 0) + ret = -ENODATA; + } else { + ret = -ENODATA; + } + + return ret; +} + bool smblib_rsbux_low(struct smb_charger *chg, int r_thr) { int r_sbu1, r_sbu2; @@ -3461,6 +4201,8 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg) { int rc; u8 stat; + union power_supply_propval val = {0, }; + int usb_present = 0; rc = smblib_read(chg, TYPE_C_SNK_STATUS_REG, &stat); if (rc < 0) { @@ -3486,6 +4228,26 @@ static int smblib_get_prop_ufp_mode(struct smb_charger *chg) break; } + /* workaround for scp cable or similar A TO C cables */ + rc = smblib_read(chg, TYPE_C_SNK_DEBUG_ACC_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read TYPE_C_STATUS_1 rc=%d\n", rc); + return POWER_SUPPLY_TYPEC_NONE; + } + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + else + usb_present = val.intval; + + if (chg->snk_debug_acc_detected && usb_present) { + return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; + } + if (stat & SNK_DEBUG_ACC_RPSTD_PRSTD_BIT && usb_present) { + chg->snk_debug_acc_detected = true; + return POWER_SUPPLY_TYPEC_SOURCE_DEFAULT; + } return POWER_SUPPLY_TYPEC_NONE; } @@ -3897,6 +4659,8 @@ static int smblib_get_typec_connector_temp_status(struct smb_charger *chg) return POWER_SUPPLY_HEALTH_COOL; } +#define HVDCP_START_CURRENT_UA 1000000 + int smblib_get_skin_temp_status(struct smb_charger *chg) { int rc; @@ -3989,14 +4753,28 @@ int smblib_set_prop_pd_current_max(struct smb_charger *chg, return rc; } +#define FLOAT_CHARGER_UA 1000000 +#define SUSPEND_CURRENT_UA 2000 static int smblib_handle_usb_current(struct smb_charger *chg, int usb_current) { int rc = 0, rp_ua, typec_mode; union power_supply_propval val = {0, }; + bool is_float = false; + + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT + && (usb_current == SUSPEND_CURRENT_UA)) + is_float = true; + + if ((usb_current > 0 && usb_current < USBIN_500MA) + || (usb_current == USBIN_900MA)) + usb_current = USBIN_500MA; if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) { - if (usb_current == -ETIMEDOUT) { + if (usb_current == -ETIMEDOUT + || is_float) { + /* we do not use USB500mA for float charger */ +#if 0 if ((chg->float_cfg & FLOAT_OPTIONS_MASK) == FORCE_FLOAT_SDP_CFG_BIT) { /* @@ -4011,6 +4789,7 @@ static int smblib_handle_usb_current(struct smb_charger *chg, rc); return rc; } +#endif if (chg->connector_type == POWER_SUPPLY_CONNECTOR_TYPEC) { @@ -4021,6 +4800,8 @@ static int smblib_handle_usb_current(struct smb_charger *chg, typec_mode = smblib_get_prop_typec_mode(chg); rp_ua = get_rp_based_dcp_current(chg, typec_mode); + if (rp_ua == DCP_CURRENT_UA) + rp_ua = FLOAT_CHARGER_UA; rc = vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); if (rc < 0) @@ -4038,6 +4819,7 @@ static int smblib_handle_usb_current(struct smb_charger *chg, * real_charger_type */ chg->real_charger_type = POWER_SUPPLY_TYPE_USB; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB; rc = vote(chg->usb_icl_votable, USB_PSY_VOTER, true, usb_current); if (rc < 0) @@ -4089,7 +4871,7 @@ int smblib_set_prop_sdp_current_max(struct smb_charger *chg, } /* handle the request only when USB is present */ - if (pval.intval) + if (pval.intval && (val->intval != 0)) rc = smblib_handle_usb_current(chg, val->intval); } else if (chg->system_suspend_supported) { if (val->intval <= USBIN_25MA) @@ -4102,6 +4884,32 @@ int smblib_set_prop_sdp_current_max(struct smb_charger *chg, return rc; } +int smblib_get_prop_type_recheck(struct smb_charger *chg, + union power_supply_propval *val) +{ + int status = 0; + + if (chg->recheck_charger) + status |= BIT(0) << 8; + + status |= chg->precheck_charger_type << 4; + status |= chg->real_charger_type; + + val->intval = status; + + return 0; +} + +int smblib_set_prop_type_recheck(struct smb_charger *chg, + const union power_supply_propval *val) +{ + if (val->intval == 0) { + cancel_delayed_work_sync(&chg->charger_type_recheck); + chg->recheck_charger = false; + } + return 0; +} + int smblib_set_prop_boost_current(struct smb_charger *chg, const union power_supply_propval *val) { @@ -4364,6 +5172,11 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); + /*set the icl to PD_UNVERIFED_CURRENT when pd is not verifed*/ + rc = vote(chg->usb_icl_votable, PD_VERIFED_VOTER, true, PD_UNVERIFED_CURRENT); + if (rc < 0) + smblib_err(chg, "Couldn't unvote PD_VERIFED_VOTER, rc=%d\n", rc); + /* * For PPS, Charge Pump is preferred over parallel charger if * present. @@ -4401,9 +5214,16 @@ int smblib_set_prop_pd_active(struct smb_charger *chg, } } - smblib_usb_pd_adapter_allowance_override(chg, + if (!chg->fake_usb_insertion) { + smblib_update_usb_type(chg); + + smblib_usb_pd_adapter_allowance_override(chg, !!chg->pd_active ? FORCE_5V : FORCE_NULL); - smblib_update_usb_type(chg); + } + +#ifdef CONFIG_THERMAL + smblib_therm_charging(chg); +#endif power_supply_changed(chg->usb_psy); return rc; } @@ -4495,6 +5315,9 @@ static int smblib_soft_jeita_arb_wa(struct smb_charger *chg) int rc = 0; bool soft_jeita; + /* we still use old soft jeita method */ + return 0; + rc = smblib_get_prop_batt_health(chg, &pval); if (rc < 0) { smblib_err(chg, "Couldn't get battery health rc=%d\n", rc); @@ -4635,12 +5458,18 @@ int smblib_get_charge_current(struct smb_charger *chg, typec_source_rd = smblib_get_prop_ufp_mode(chg); - /* QC 2.0/3.0 adapter */ - if (apsd_result->bit & (QC_3P0_BIT | QC_2P0_BIT)) { + /* QC 3.0 adapter */ + if (apsd_result->bit & QC_3P0_BIT) { *total_current_ua = HVDCP_CURRENT_UA; return 0; } + /* QC 2.0 adapter */ + if (apsd_result->bit & QC_2P0_BIT) { + *total_current_ua = HVDCP2_CURRENT_UA; + return 0; + } + if (non_compliant && !chg->typec_legacy_use_rp_icl) { switch (apsd_result->bit) { case CDP_CHARGER_BIT: @@ -4819,6 +5648,33 @@ static void smblib_eval_chg_termination(struct smb_charger *chg, u8 batt_status) } } +irqreturn_t dcin_uv_handler(int irq, void *data) +{ + struct smb_irq_data *irq_data = data; + struct smb_charger *chg = irq_data->parent_data; + + int rc; + u8 stat; + + rc = smblib_read(chg, POWER_PATH_STATUS_REG, &stat); + if (rc < 0) { + smblib_err(chg, "Couldn't read POWER_PATH_STATUS rc=%d\n", + rc); + return IRQ_HANDLED; + } + + if ((stat & POWER_PATH_MASK) == 0x2) { /*power by battery*/ + chg->fake_dc_on = 1; /*use for delay 1.8s*/ + chg->fake_dc_flag = 1; + schedule_delayed_work(&chg->dc_plug_out_delay_work, + msecs_to_jiffies(1800)); + vote(chg->awake_votable, DC_UV_AWAKE_VOTER, true, 0); + } + smblib_dbg(chg, PR_WLS, "Delay dc plug out and power path 0x%x\n", stat); + + return IRQ_HANDLED; +} + irqreturn_t chg_state_change_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; @@ -4851,7 +5707,6 @@ irqreturn_t batt_temp_changed_irq_handler(int irq, void *data) int rc; smblib_dbg(chg, PR_INTERRUPT, "IRQ: %s\n", irq_data->name); - if (chg->jeita_configured != JEITA_CFG_COMPLETE) return IRQ_HANDLED; @@ -4862,6 +5717,10 @@ irqreturn_t batt_temp_changed_irq_handler(int irq, void *data) return IRQ_HANDLED; } + /* we still use old soft jeita method */ + rerun_election(chg->fcc_votable); + power_supply_changed(chg->batt_psy); + return IRQ_HANDLED; } @@ -4959,6 +5818,7 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) /* Workaround for non-QC2.0-compliant chargers follows */ if (!chg->qc2_unsupported_voltage && + !chg->qc2_unsupported && apsd->pst == POWER_SUPPLY_TYPE_USB_HVDCP) { rc = smblib_read(chg, QC_CHANGE_STATUS_REG, &stat); if (rc < 0) @@ -5004,6 +5864,17 @@ irqreturn_t usbin_uv_irq_handler(int irq, void *data) rc); smblib_rerun_apsd(chg); + + pr_info("qc2_unsupported charger detected\n"); + rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT); + if (rc < 0) + pr_err("Failed to force 5V\n"); + rc = smblib_set_opt_switcher_freq(chg, chg->chg_freq.freq_5V); + if (rc < 0) + pr_err("Failed to set chg_freq.freq_5V\n"); + vote(chg->usb_icl_votable, QC2_UNSUPPORTED_VOTER, true, + QC2_UNSUPPORTED_UA); + chg->qc2_unsupported = true; } return IRQ_HANDLED; @@ -5063,6 +5934,46 @@ irqreturn_t icl_change_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static void smblib_cc_un_compliant_charge_work(struct work_struct *work) +{ + union power_supply_propval val = {0, }; + int rc, usb_present = 0; + + struct smb_charger *chg = container_of(work, struct smb_charger, + cc_un_compliant_charge_work.work); + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return; + } + + usb_present = val.intval; + + if (usb_present && chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { + chg->real_charger_type = POWER_SUPPLY_TYPE_USB_FLOAT; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_FLOAT; + if ((strcmp(get_effective_client(chg->usb_icl_votable), "OTG_VOTER") == 0) && + (get_effective_result(chg->usb_icl_votable) == 0)) + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); + + if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER) != 500000) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, 500000); + } + + if (usb_present + && (chg->typec_mode == POWER_SUPPLY_TYPEC_NONE || + chg->typec_mode == POWER_SUPPLY_TYPEC_NON_COMPLIANT || + chg->snk_debug_acc_detected == true) + && (chg->cc_un_compliant_detected == false)) { + chg->cc_un_compliant_detected = true; + //smblib_apsd_enable(chg, true); + smblib_hvdcp_detect_enable(chg, true); + smblib_rerun_apsd_if_required(chg); + } +} + + static void smblib_micro_usb_plugin(struct smb_charger *chg, bool vbus_rising) { if (!vbus_rising) { @@ -5089,6 +6000,7 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) vbus_rising = (bool)(stat & USBIN_PLUGIN_RT_STS_BIT); if (vbus_rising) { + vote(chg->awake_votable, CHG_AWAKE_VOTER, true, 0); /* Remove FCC_STEPPER 1.5A init vote to allow FCC ramp up */ if (chg->fcc_stepper_enable) vote(chg->fcc_votable, FCC_STEPPER_VOTER, false, 0); @@ -5106,12 +6018,21 @@ void smblib_usb_plugin_hard_reset_locked(struct smb_charger *chg) } } + cancel_delayed_work_sync(&chg->charger_type_recheck); + chg->recheck_charger = false; + chg->precheck_charger_type = POWER_SUPPLY_TYPE_UNKNOWN; + if (chg->cc_un_compliant_detected) { + smblib_hvdcp_detect_enable(chg, false); + chg->cc_un_compliant_detected = false; + } + + vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0); + /* Force 1500mA FCC on USB removal if fcc stepper is enabled */ if (chg->fcc_stepper_enable) vote(chg->fcc_votable, FCC_STEPPER_VOTER, true, 1500000); } - power_supply_changed(chg->usb_psy); smblib_dbg(chg, PR_INTERRUPT, "IRQ: usbin-plugin %s\n", vbus_rising ? "attached" : "detached"); @@ -5137,6 +6058,14 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) chg->chg_freq.freq_removal); if (vbus_rising) { + if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE + && smblib_get_prop_dfp_mode(chg) + != POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { + chg->fake_usb_insertion = true; + return; + } + + vote(chg->awake_votable, CHG_AWAKE_VOTER, true, 0); cancel_delayed_work_sync(&chg->pr_swap_detach_work); vote(chg->awake_votable, DETACH_DETECT_VOTER, false, 0); rc = smblib_request_dpdm(chg, true); @@ -5157,7 +6086,18 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) vote(chg->awake_votable, PL_DELAY_VOTER, true, 0); schedule_delayed_work(&chg->pl_enable_work, msecs_to_jiffies(PL_DELAY_MS)); + schedule_delayed_work(&chg->charger_type_recheck, + msecs_to_jiffies(CHARGER_RECHECK_DELAY_MS)); + schedule_delayed_work(&chg->cc_un_compliant_charge_work, + msecs_to_jiffies(CC_UN_COMPLIANT_START_DELAY_MS)); } else { + if (chg->fake_usb_insertion) { + chg->fake_usb_insertion = false; + return; + } + + cancel_delayed_work_sync(&chg->charger_type_recheck); + /* Disable SW Thermal Regulation */ rc = smblib_set_sw_thermal_regulation(chg, false); if (rc < 0) @@ -5213,6 +6153,13 @@ void smblib_usb_plugin_locked(struct smb_charger *chg) if (rc < 0) smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + if (chg->cc_un_compliant_detected) { + smblib_hvdcp_detect_enable(chg, false); + chg->cc_un_compliant_detected = false; + } + chg->recheck_charger = false; + chg->precheck_charger_type = POWER_SUPPLY_TYPE_UNKNOWN; + vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0); smblib_update_usb_type(chg); } @@ -5256,6 +6203,135 @@ static void smblib_handle_sdp_enumeration_done(struct smb_charger *chg, rising ? "rising" : "falling"); } +static void smblib_raise_qc3_vbus_work(struct work_struct *work) +{ + union power_supply_propval val = {0, }; + int i, usb_present = 0, vbus_now = 0; + int vol_qc_ab_thr = 0; + int rc; + struct smb_charger *chg = container_of(work, struct smb_charger, + raise_qc3_vbus_work.work); + + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return; + } + + usb_present = val.intval; + if (usb_present) { + chg->raise_vbus_to_detect = true; + for (i = 0; i < MAX_PULSE; i++) { + rc = smblib_dp_pulse(chg); + msleep(40); + } + msleep(200); + rc = smblib_get_prop_usb_present(chg, &val); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return; + } + + usb_present = val.intval; + pr_info("usb_present is %d\n", usb_present); + if (!usb_present) { + chg->raise_vbus_to_detect = false; + rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT); + if (rc < 0) + pr_err("Failed to force 5V\n"); + return; + } + + rc = smblib_get_usb_in_voltage_now(chg, &val); + if (rc < 0) + pr_err("Couldn't get usb voltage rc=%d\n", rc); + vbus_now = val.intval; + pr_info("vbus_now is %d\n", vbus_now); + + if (chg->snk_debug_acc_detected && usb_present) + vol_qc_ab_thr = VOL_THR_FOR_QC_CLASS_AB + + COMP_FOR_LOW_RESISTANCE_CABLE; + else + vol_qc_ab_thr = VOL_THR_FOR_QC_CLASS_AB; + if (vbus_now <= vol_qc_ab_thr) { + chg->is_qc_class_a = true; + vote(chg->fcc_votable, + CLASSA_QC_FCC_VOTER, true, QC_CLASS_A_CURRENT_UA); + } else { + chg->is_qc_class_b = true; + if (chg->usb_psy) + power_supply_changed(chg->usb_psy); + } + rc = smblib_force_vbus_voltage(chg, FORCE_5V_BIT); + if (rc < 0) + pr_err("Failed to force 5V\n"); + if (chg->is_qc_class_a) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CLASS_A_MAX_UA); + else + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CURRENT_UA); + /* select charge pump as second charger */ + rc = smblib_select_sec_charger(chg, POWER_SUPPLY_CHARGER_SEC_CP, + POWER_SUPPLY_CP_HVDCP3, false); + if (rc < 0) + dev_err(chg->dev, + "Couldn't enable secondary chargers rc=%d\n", rc); +#ifdef CONFIG_THERMAL + if (chg->cp_reason == POWER_SUPPLY_CP_HVDCP3) + smblib_therm_charging(chg); +#endif + chg->raise_vbus_to_detect = false; + } +} + +struct quick_charge adapter_cap[10] = { + { POWER_SUPPLY_TYPE_USB, QUICK_CHARGE_NORMAL }, + { POWER_SUPPLY_TYPE_USB_DCP, QUICK_CHARGE_NORMAL }, + { POWER_SUPPLY_TYPE_USB_CDP, QUICK_CHARGE_NORMAL }, + { POWER_SUPPLY_TYPE_USB_ACA, QUICK_CHARGE_NORMAL }, + { POWER_SUPPLY_TYPE_USB_FLOAT, QUICK_CHARGE_NORMAL }, + { POWER_SUPPLY_TYPE_USB_PD, QUICK_CHARGE_FAST }, + { POWER_SUPPLY_TYPE_USB_HVDCP, QUICK_CHARGE_FAST }, + { POWER_SUPPLY_TYPE_USB_HVDCP_3, QUICK_CHARGE_FAST }, + { POWER_SUPPLY_TYPE_WIRELESS, QUICK_CHARGE_FAST }, + {0, 0}, +}; + +int smblib_get_quick_charge_type(struct smb_charger *chg) +{ + int i = 0, rc; + union power_supply_propval pval = {0, }; + + if (!chg) { + dev_err(chg->dev, "get quick charge type faied\n"); + return -EINVAL; + } + + rc = smblib_get_prop_batt_status(chg, &pval); + if (rc < 0) + return -EINVAL; + + if (pval.intval == POWER_SUPPLY_STATUS_DISCHARGING) + return 0; + + if ((chg->real_charger_type == POWER_SUPPLY_TYPE_USB_PD) && chg->pd_verifed) { + return QUICK_CHARGE_FLASH; + } + + if (chg->is_qc_class_b) + return QUICK_CHARGE_FLASH; + + while (adapter_cap[i].adap_type != 0) { + if (chg->real_charger_type == adapter_cap[i].adap_type) { + return adapter_cap[i].adap_cap; + } + i++; + } + + return 0; +} + #define APSD_EXTENDED_TIMEOUT_MS 400 /* triggers when HVDCP 3.0 authentication has finished */ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, @@ -5276,13 +6352,20 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, if (apsd_result->bit & QC_3P0_BIT) { /* for QC3, switch to CP if present */ if (chg->sec_cp_present) { - rc = smblib_select_sec_charger(chg, - POWER_SUPPLY_CHARGER_SEC_CP, - POWER_SUPPLY_CP_HVDCP3, false); - if (rc < 0) - dev_err(chg->dev, - "Couldn't enable secondary chargers rc=%d\n", - rc); + if (!chg->qc_class_ab) { + rc = smblib_select_sec_charger(chg, + POWER_SUPPLY_CHARGER_SEC_CP, + POWER_SUPPLY_CP_HVDCP3, false); + if (rc < 0) + dev_err(chg->dev, + "Couldn't enable secondary chargers rc=%d\n", + rc); + } else if (!chg->detect_low_power_qc3_charger) { + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_START_CURRENT_UA); + schedule_delayed_work(&chg->raise_qc3_vbus_work, 0); + chg->detect_low_power_qc3_charger = true; + } } /* QC3.5 detection timeout */ @@ -5296,6 +6379,14 @@ static void smblib_handle_hvdcp_3p0_auth_done(struct smb_charger *chg, msecs_to_jiffies(APSD_EXTENDED_TIMEOUT_MS) + jiffies); } + } else if (apsd_result->bit & QC_2P0_BIT + && !chg->qc2_unsupported) { + pr_info("force 9V for QC2 charger\n"); + rc = smblib_force_vbus_voltage(chg, FORCE_9V_BIT); + if (rc < 0) + pr_err("Failed to force 9V\n"); + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP2_CURRENT_UA); } smblib_dbg(chg, PR_INTERRUPT, "IRQ: hvdcp-3p0-auth-done rising; %s detected\n", @@ -5313,8 +6404,17 @@ static void smblib_handle_hvdcp_check_timeout(struct smb_charger *chg, CHARGER_TYPE_VOTER, false, 0); vote(chg->hdc_irq_disable_votable, CHARGER_TYPE_VOTER, false, 0); - vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - HVDCP_CURRENT_UA); + if (!chg->raise_vbus_to_detect) { + if (chg->is_qc_class_a) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CLASS_A_MAX_UA); + else if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP2_CURRENT_UA); + else + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + HVDCP_CURRENT_UA); + } } else { /* A plain DCP, enforce DCP ICL if specified */ vote(chg->usb_icl_votable, DCP_VOTER, @@ -5375,25 +6475,38 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) /* if flash is active force 500mA */ vote(chg->usb_icl_votable, USB_PSY_VOTER, true, is_flash_active(chg) ? - SDP_CURRENT_UA : SDP_100_MA); + SDP_CURRENT_UA : USBIN_500MA); } vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, false, 0); break; case POWER_SUPPLY_TYPE_USB_CDP: + if (is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, CDP_CURRENT_UA); break; case POWER_SUPPLY_TYPE_USB_DCP: + if (is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); rp_ua = get_rp_based_dcp_current(chg, typec_mode); vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, rp_ua); break; case POWER_SUPPLY_TYPE_USB_FLOAT: + if (is_client_vote_enabled(chg->usb_icl_votable, + USB_PSY_VOTER)) + vote(chg->usb_icl_votable, USB_PSY_VOTER, false, 0); /* * limit ICL to 100mA, the USB driver will enumerate to check * if this is a SDP and appropriately set the current */ - vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, - SDP_100_MA); + if (!chg->recheck_charger) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + SDP_100_MA); + else + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, + FLOAT_CHARGER_UA); break; case POWER_SUPPLY_TYPE_UNKNOWN: default: @@ -5403,6 +6516,20 @@ static void update_sw_icl_max(struct smb_charger *chg, int pst) } } +#ifdef CONFIG_THERMAL +static void determine_thermal_current(struct smb_charger *chg) +{ + if (chg->system_temp_level > 0 + && chg->system_temp_level < (chg->thermal_levels - 1)) { + /* + * consider thermal limit only when it is active and not at + * the highest level + */ + smblib_therm_charging(chg); + } +} +#endif + static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) { const struct apsd_result *apsd_result; @@ -5420,14 +6547,30 @@ static void smblib_handle_apsd_done(struct smb_charger *chg, bool rising) case FLOAT_CHARGER_BIT: if (chg->use_extcon) smblib_notify_device_mode(chg, true); + if (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, 500000); break; case OCP_CHARGER_BIT: case DCP_CHARGER_BIT: + if (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER){ + chg->real_charger_type = POWER_SUPPLY_TYPE_USB_FLOAT; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_FLOAT; + if ((strcmp(get_effective_client(chg->usb_icl_votable), "OTG_VOTER") == 0) && + (get_effective_result(chg->usb_icl_votable) == 0)) + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); + + if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER) != 500000) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, 500000); + } break; default: break; } +#ifdef CONFIG_THERMAL + determine_thermal_current(chg); +#endif + smblib_dbg(chg, PR_INTERRUPT, "IRQ: apsd-done rising; %s detected\n", apsd_result->name); } @@ -5438,6 +6581,8 @@ irqreturn_t usb_source_change_irq_handler(int irq, void *data) struct smb_charger *chg = irq_data->parent_data; int rc = 0; u8 stat; + if (chg->fake_usb_insertion) + return IRQ_HANDLED; /* PD session is ongoing, ignore BC1.2 and QC detection */ if (chg->pd_active) @@ -5529,10 +6674,14 @@ enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, chg->lpd_stage = LPD_STAGE_NONE; chg->lpd_reason = LPD_NONE; + if (chg->support_liquid == true) { + schedule_work(&chg->lpd_disable_chg_work); + } + return ALARMTIMER_NORESTART; } -#define RSBU_K_300K_UV 3000000 +#define RSBU_K_300K_UV 3000000 static bool smblib_src_lpd(struct smb_charger *chg) { union power_supply_propval pval; @@ -5562,6 +6711,13 @@ static bool smblib_src_lpd(struct smb_charger *chg) break; } + chg->typec_mode = smblib_get_prop_typec_mode(chg); + if ((chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) + && (chg->support_liquid == true)) { + lpd_flag = false; + return lpd_flag; + } + if (lpd_flag) { chg->lpd_stage = LPD_STAGE_COMMIT; pval.intval = POWER_SUPPLY_TYPEC_PR_SINK; @@ -5570,6 +6726,17 @@ static bool smblib_src_lpd(struct smb_charger *chg) smblib_err(chg, "Couldn't write 0x%02x to TYPE_C_INTRPT_ENB_SOFTWARE_CTRL rc=%d\n", pval.intval, rc); chg->lpd_reason = LPD_MOISTURE_DETECTED; + + chg->lpd_status = true; + + if (chg->support_liquid == true) { + vote(chg->usb_icl_votable, LIQUID_DETECTION_VOTER, true, 0); + if (chg->batt_psy) + power_supply_changed(chg->batt_psy); + } + alarm_start_relative(&chg->lpd_recheck_timer, + ms_to_ktime(15000)); + chg->moisture_present = true; alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(60000)); @@ -5596,7 +6763,30 @@ static void typec_src_fault_condition_cfg(struct smb_charger *chg, bool src) static void typec_sink_insertion(struct smb_charger *chg) { - int rc; + int rc = 0; + int usb_present = 0; + int typec_mode; + union power_supply_propval pval = {0, }; + + rc = smblib_get_prop_usb_present(chg, &pval); + if (rc < 0) { + smblib_err(chg, "Couldn't get usb present rc = %d\n", rc); + return; + } + + usb_present = pval.intval; + + typec_mode = smblib_get_prop_typec_mode(chg); + if (usb_present && typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER) { + chg->real_charger_type = POWER_SUPPLY_TYPE_USB_FLOAT; + chg->usb_psy_desc.type = POWER_SUPPLY_TYPE_USB_FLOAT; + if (get_client_vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER) != 500000) + vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, 500000); + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); + power_supply_changed(chg->batt_psy); + } else { + vote(chg->usb_icl_votable, OTG_VOTER, true, 0); + } typec_src_fault_condition_cfg(chg, true); rc = smblib_set_charge_param(chg, &chg->param.freq_switcher, @@ -5652,6 +6842,7 @@ static void typec_sink_removal(struct smb_charger *chg) { int rc; + vote(chg->usb_icl_votable, OTG_VOTER, false, 0); typec_src_fault_condition_cfg(chg, false); rc = smblib_set_charge_param(chg, &chg->param.freq_switcher, chg->chg_freq.freq_removal); @@ -5682,6 +6873,8 @@ static void typec_src_removal(struct smb_charger *chg) "Couldn't disable secondary charger rc=%d\n", rc); chg->qc3p5_detected = false; + chg->snk_debug_acc_detected = false; + typec_src_fault_condition_cfg(chg, false); smblib_hvdcp_detect_enable(chg, false); smblib_update_usb_type(chg); @@ -5698,6 +6891,7 @@ static void typec_src_removal(struct smb_charger *chg) } cancel_delayed_work_sync(&chg->pl_enable_work); + cancel_delayed_work_sync(&chg->raise_qc3_vbus_work); /* reset input current limit voters */ vote(chg->usb_icl_votable, SW_ICL_MAX_VOTER, true, @@ -5723,6 +6917,11 @@ static void typec_src_removal(struct smb_charger *chg) vote(chg->pl_enable_votable_indirect, USBIN_I_VOTER, false, 0); vote(chg->pl_enable_votable_indirect, USBIN_V_VOTER, false, 0); vote(chg->awake_votable, PL_DELAY_VOTER, false, 0); + vote(chg->awake_votable, CHG_AWAKE_VOTER, false, 0); + vote(chg->fcc_votable, CLASSA_QC_FCC_VOTER, false, 0); + vote(chg->usb_icl_votable, QC_A_CP_ICL_MAX_VOTER, false, 0); + vote(chg->usb_icl_votable, QC2_UNSUPPORTED_VOTER, false, 0); + vote(chg->usb_icl_votable, PD_VERIFED_VOTER, false, 0); /* Remove SW thermal regulation WA votes */ vote(chg->usb_icl_votable, SW_THERM_REGULATION_VOTER, false, 0); @@ -5801,6 +7000,17 @@ static void typec_src_removal(struct smb_charger *chg) del_timer_sync(&chg->apsd_timer); chg->apsd_ext_timeout = false; + chg->detect_low_power_qc3_charger = false; + chg->raise_vbus_to_detect = false; + chg->is_qc_class_a = false; + chg->is_qc_class_b = false; + chg->high_vbus_detected = false; + chg->qc2_unsupported = false; + chg->cc_un_compliant_detected = false; + chg->recheck_charger = false; + + if (chg->pd_verifed) + chg->pd_verifed = false; } static void typec_mode_unattached(struct smb_charger *chg) @@ -5963,6 +7173,9 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) if (attached) { smblib_lpd_clear_ra_open_work(chg); + if (chg->lpd_status) + chg->lpd_status = false; + rc = smblib_read(chg, TYPE_C_MISC_STATUS_REG, &stat); if (rc < 0) { smblib_err(chg, "Couldn't read TYPE_C_MISC_STATUS_REG rc=%d\n", @@ -5982,6 +7195,7 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) } else { chg->sink_src_mode = SINK_MODE; typec_src_insertion(chg); + smblib_wireless_set_enable(chg, false); } } else { @@ -5992,6 +7206,7 @@ irqreturn_t typec_attach_detach_irq_handler(int irq, void *data) case SINK_MODE: case AUDIO_ACCESS_MODE: typec_src_removal(chg); + smblib_wireless_set_enable(chg, true); break; case UNATTACHED_MODE: default: @@ -6179,14 +7394,150 @@ irqreturn_t dcin_uv_irq_handler(int irq, void *data) return IRQ_HANDLED; } +static int smblib_get_wireless_output_vol(struct smb_charger *chg) +{ + + int rc,wireless_vout = 0; + + rc = iio_read_channel_processed(chg->iio.vph_v_chan, + &wireless_vout); + if (rc < 0) { + smblib_err(chg, "Couldn't get vph vol rc = %d\n", + rc); + return -ENODATA; + } + wireless_vout *= 2; + wireless_vout /= 100000; + wireless_vout *= 100000; + + return wireless_vout; + +} + +int smblib_set_wirless_cp_enable(struct smb_charger *chg, + const union power_supply_propval *val) +{ + union power_supply_propval pval; + int wireless_vout = 0; + int rc; + + wireless_vout = smblib_get_wireless_output_vol(chg); + if (wireless_vout < 0) { + dev_err(chg->dev, "Couldn't get vph_pwr wireless_vout=%d\n", + wireless_vout); + return -ENODATA; + } + + if (chg->flag_dc_present && val->intval) { + pval.intval = wireless_vout; + rc = smblib_set_prop_voltage_wls_output(chg, &pval); + if (rc < 0) + dev_err(chg->dev, "Couldn't set dc voltage to 2*vph rc=%d\n", + rc); + + rc = smblib_select_sec_charger(chg, POWER_SUPPLY_CHARGER_SEC_CP, + POWER_SUPPLY_CP_WIRELESS, false); + if (rc < 0) + dev_err(chg->dev, + "Couldn't enable secondary chargers rc=%d\n", rc); + } else + smblib_dbg(chg, PR_WLS, "dcin_not present or usbin_present\n"); + + return 0; +} + +int smblib_set_wirless_power_good_enable(struct smb_charger *chg, + const union power_supply_propval *val) +{ + int rc = 0; + + chg->power_good_en = val->intval; + if (chg->power_good_en) { + chg->fake_dc_on = 1; + chg->fake_dc_flag = 0; + chg->last_batt_stat = 0; + cancel_delayed_work(&chg->dc_plug_out_delay_work); + vote(chg->awake_votable, DC_UV_AWAKE_VOTER, false, 0); + + } + else { + if (!chg->fake_dc_flag) + chg->fake_dc_on = 0; + /* step1: enter dc suspend */ + rc = vote(chg->dc_suspend_votable, OTG_VOTER, + true, 0); + + /* step2: force dcin_en low */ + rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, + DCIN_EN_OVERRIDE_BIT | DCIN_EN_BIT, + DCIN_EN_OVERRIDE_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure dc_en override rc=%d\n", rc); + return rc; + } + + /* step3: enable pull-down on dcin_pon and mid_chg */ + rc = smblib_masked_write(chg, DCIN_CMD_PULLDOWN_REG, + DCIN_PULLDOWN_EN_BIT | DCIN_MID_PULLDOWN_BIT, + DCIN_PULLDOWN_EN_BIT | DCIN_MID_PULLDOWN_BIT); + if (rc < 0) { + dev_err(chg->dev, "Couldn't enable dcin_pulldown rc=%d\n", rc); + return rc; + } + /* wait 10ms to pull mid_chg lower than Vsys+Vrevi */ + msleep(10); + + /* step4: disable pull-down on dcin_pon and mid_chg */ + rc = smblib_masked_write(chg, DCIN_CMD_PULLDOWN_REG, + DCIN_PULLDOWN_EN_BIT | DCIN_MID_PULLDOWN_BIT, + 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't disable dcin_pulldown rc=%d\n", rc); + return rc; + } + + /* step5: remove dcin_en low */ + rc = smblib_masked_write(chg, DCIN_CMD_IL_REG, + DCIN_EN_OVERRIDE_BIT | DCIN_EN_BIT, + 0); + if (rc < 0) { + dev_err(chg->dev, "Couldn't configure dc_en override rc=%d\n", rc); + return rc; + } + + /* step6: exit dc suspend */ + rc = vote(chg->dc_suspend_votable, OTG_VOTER, + false, 0); + } + power_supply_changed(chg->dc_psy); + power_supply_changed(chg->batt_psy); + if (chg->wls_psy) + power_supply_changed(chg->wls_psy); + + return 0; +} + +static void smblib_dc_plug_out_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + dc_plug_out_delay_work.work); + + chg->fake_dc_on = 0; /*use for delay 1.8s*/ + chg->fake_dc_flag = 0; + chg->last_batt_stat = 0; + power_supply_changed(chg->dc_psy); + vote(chg->awake_votable, DC_UV_AWAKE_VOTER, false, 0); +} + irqreturn_t dc_plugin_irq_handler(int irq, void *data) { struct smb_irq_data *irq_data = data; struct smb_charger *chg = irq_data->parent_data; - union power_supply_propval pval; + union power_supply_propval pval = {0, }; int input_present; bool dcin_present, vbus_present; - int rc, wireless_vout = 0; + //int rc, wireless_vout = 0; + int rc; int sec_charger; rc = smblib_get_prop_vph_voltage_now(chg, &pval); @@ -6194,15 +7545,26 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) return IRQ_HANDLED; /* 2*VPH, with a granularity of 100mV */ - wireless_vout = ((pval.intval * 2) / 100000) * 100000; + //wireless_vout = ((pval.intval * 2) / 100000) * 100000; rc = smblib_is_input_present(chg, &input_present); if (rc < 0) return IRQ_HANDLED; + chg->idtp_psy = power_supply_get_by_name("idt"); + if (!chg->idtp_psy) + dev_err(chg->dev, "Could not get idtp psy\n"); + dcin_present = input_present & INPUT_PRESENT_DC; vbus_present = input_present & INPUT_PRESENT_USB; + /* when dcin present and in otg mode, set vbus present to 0*/ + if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE + && smblib_get_prop_dfp_mode(chg) + != POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER + && dcin_present) + vbus_present = 0; + if (dcin_present && !vbus_present) { cancel_work_sync(&chg->dcin_aicl_work); @@ -6217,6 +7579,15 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) smblib_dbg(chg, (PR_WLS | PR_INTERRUPT), "reset: icl: 100 mA\n"); if (chg->sec_cp_present) { + chg->flag_dc_present = 1; + vote(chg->awake_votable, DC_AWAKE_VOTER, true, 0); + if (chg->idtp_psy) { + pval.intval = true; + power_supply_set_property(chg->idtp_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); + } + +/* pval.intval = wireless_vout; rc = smblib_set_prop_voltage_wls_output(chg, &pval); if (rc < 0) @@ -6229,6 +7600,7 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) if (rc < 0) dev_err(chg->dev, "Couldn't enable secondary chargers rc=%d\n", rc); +*/ } else { /* * If no secondary charger is present, commence @@ -6243,15 +7615,25 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) schedule_work(&chg->dcin_aicl_work); } else { - if (chg->cp_reason == POWER_SUPPLY_CP_WIRELESS) { - sec_charger = chg->sec_pl_present ? + vote(chg->awake_votable, DC_AWAKE_VOTER, false, 0); + vote(chg->dc_icl_votable, DCIN_ADAPTER_VOTER, true, 100000); + chg->flag_dc_present = 0; + chg->cp_reason = POWER_SUPPLY_CP_NONE; + sec_charger = chg->sec_pl_present ? POWER_SUPPLY_CHARGER_SEC_PL : POWER_SUPPLY_CHARGER_SEC_NONE; - rc = smblib_select_sec_charger(chg, sec_charger, - POWER_SUPPLY_CP_NONE, false); - if (rc < 0) - dev_err(chg->dev, "Couldn't disable secondary charger rc=%d\n", - rc); + rc = smblib_select_sec_charger(chg, sec_charger, + POWER_SUPPLY_CP_NONE, false); + + if (rc < 0) + dev_err(chg->dev, + "Couldn't disable secondary charger rc=%d\n", + rc); + + if (chg->idtp_psy) { + pval.intval = false; + power_supply_set_property(chg->idtp_psy, + POWER_SUPPLY_PROP_PRESENT, &pval); } vote(chg->dc_suspend_votable, CHG_TERMINATION_VOTER, false, 0); @@ -6260,6 +7642,8 @@ irqreturn_t dc_plugin_irq_handler(int irq, void *data) } power_supply_changed(chg->dc_psy); + if (chg->wls_psy) + power_supply_changed(chg->wls_psy); smblib_dbg(chg, (PR_WLS | PR_INTERRUPT), "dcin_present= %d, usbin_present= %d, cp_reason = %d\n", dcin_present, vbus_present, chg->cp_reason); @@ -7015,6 +8399,9 @@ static void jeita_update_work(struct work_struct *work) } } + chg->jeita_configured = JEITA_CFG_COMPLETE; + return; + chg->jeita_soft_fcc[0] = chg->jeita_soft_fcc[1] = -EINVAL; chg->jeita_soft_fv[0] = chg->jeita_soft_fv[1] = -EINVAL; max_fcc_ma = max_fv_uv = -EINVAL; @@ -7101,6 +8488,13 @@ static void smblib_lpd_ra_open_work(struct work_struct *work) if (!(stat & TYPEC_WATER_DETECTION_STATUS_BIT) || (stat & TYPEC_TCCDEBOUNCE_DONE_STATUS_BIT)) { chg->lpd_stage = LPD_STAGE_NONE; + chg->lpd_status = false; + + if (chg->support_liquid == true) { + vote(chg->usb_icl_votable, LIQUID_DETECTION_VOTER, false, 0); + if (chg->batt_psy) + power_supply_changed(chg->batt_psy); + } goto out; } @@ -7129,8 +8523,16 @@ static void smblib_lpd_ra_open_work(struct work_struct *work) } chg->lpd_reason = LPD_MOISTURE_DETECTED; + + chg->lpd_status = true; + chg->moisture_present = true; + if (chg->support_liquid == true) { + vote(chg->usb_icl_votable, LIQUID_DETECTION_VOTER, true, 0); + if (chg->batt_psy) + power_supply_changed(chg->batt_psy); + } } else { /* Floating cable, disable water detection irq temporarily */ rc = smblib_masked_write(chg, TYPE_C_INTERRUPT_EN_CFG_2_REG, @@ -7153,12 +8555,22 @@ static void smblib_lpd_ra_open_work(struct work_struct *work) chg->lpd_reason = LPD_FLOATING_CABLE; } - /* recheck in 60 seconds */ - alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(60000)); + /* recheck in 15 seconds */ + alarm_start_relative(&chg->lpd_recheck_timer, ms_to_ktime(15000)); out: vote(chg->awake_votable, LPD_VOTER, false, 0); } +static void smblib_lpd_disable_chg_work(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + lpd_disable_chg_work); + + vote(chg->usb_icl_votable, LIQUID_DETECTION_VOTER, false, 0); + if (chg->batt_psy) + power_supply_changed(chg->batt_psy); +} + static void smblib_lpd_detach_work(struct work_struct *work) { struct smb_charger *chg = container_of(work, struct smb_charger, @@ -7168,6 +8580,50 @@ static void smblib_lpd_detach_work(struct work_struct *work) chg->lpd_stage = LPD_STAGE_NONE; } +static void smblib_charger_type_recheck(struct work_struct *work) +{ + struct smb_charger *chg = container_of(work, struct smb_charger, + charger_type_recheck.work); + int recheck_time = TYPE_RECHECK_TIME_5S; + static int last_charger_type, check_count; + int rc; + smblib_update_usb_type(chg); + + if (last_charger_type != chg->real_charger_type) + check_count--; + last_charger_type = chg->real_charger_type; + + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP_3 || + chg->real_charger_type == POWER_SUPPLY_TYPE_USB_HVDCP || + chg->pd_active || (check_count >= TYPE_RECHECK_COUNT) || + ((chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) && + (chg->typec_mode == POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER))) { + check_count = 0; + return; + } + + if (smblib_get_prop_dfp_mode(chg) != POWER_SUPPLY_TYPEC_NONE) + goto check_next; + + if (!chg->recheck_charger) + chg->precheck_charger_type = chg->real_charger_type; + chg->recheck_charger = true; + + if (chg->real_charger_type == POWER_SUPPLY_TYPE_USB_FLOAT) { + rc = smblib_request_dpdm(chg, false); + if (rc < 0) + smblib_err(chg, "Couldn't disable DPDM rc=%d\n", rc); + + msleep(500); + } + smblib_rerun_apsd_if_required(chg); + +check_next: + check_count++; + schedule_delayed_work(&chg->charger_type_recheck, + msecs_to_jiffies(recheck_time)); +} + static char *dr_mode_text[] = { "ufp", "dfp", "none" }; @@ -7355,6 +8811,14 @@ static int smblib_create_votables(struct smb_charger *chg) return rc; } + chg->dc_icl_votable = create_votable("DC_ICL", VOTE_MIN, + smblib_dc_icl_vote_callback, + chg); + if (IS_ERR(chg->dc_icl_votable)) { + rc = PTR_ERR(chg->dc_icl_votable); + return rc; + } + chg->awake_votable = create_votable("AWAKE", VOTE_SET_ANY, smblib_awake_vote_callback, chg); @@ -7464,6 +8928,7 @@ int smblib_init(struct smb_charger *chg) INIT_WORK(&chg->pl_update_work, pl_update_work); INIT_WORK(&chg->jeita_update_work, jeita_update_work); INIT_WORK(&chg->dcin_aicl_work, dcin_aicl_work); + INIT_WORK(&chg->lpd_disable_chg_work, smblib_lpd_disable_chg_work); INIT_DELAYED_WORK(&chg->clear_hdc_work, clear_hdc_work); INIT_DELAYED_WORK(&chg->icl_change_work, smblib_icl_change_work); INIT_DELAYED_WORK(&chg->pl_enable_work, smblib_pl_enable_work); @@ -7471,8 +8936,13 @@ int smblib_init(struct smb_charger *chg) INIT_DELAYED_WORK(&chg->bb_removal_work, smblib_bb_removal_work); INIT_DELAYED_WORK(&chg->lpd_ra_open_work, smblib_lpd_ra_open_work); INIT_DELAYED_WORK(&chg->lpd_detach_work, smblib_lpd_detach_work); + INIT_DELAYED_WORK(&chg->raise_qc3_vbus_work, smblib_raise_qc3_vbus_work); + INIT_DELAYED_WORK(&chg->charger_type_recheck, smblib_charger_type_recheck); + INIT_DELAYED_WORK(&chg->cc_un_compliant_charge_work, + smblib_cc_un_compliant_charge_work); INIT_DELAYED_WORK(&chg->thermal_regulation_work, smblib_thermal_regulation_work); + INIT_DELAYED_WORK(&chg->dc_plug_out_delay_work, smblib_dc_plug_out_work); INIT_DELAYED_WORK(&chg->usbov_dbc_work, smblib_usbov_dbc_work); INIT_DELAYED_WORK(&chg->role_reversal_check, smblib_dual_role_check_work); @@ -7524,6 +8994,7 @@ int smblib_init(struct smb_charger *chg) chg->sec_chg_selected = POWER_SUPPLY_CHARGER_SEC_NONE; chg->cp_reason = POWER_SUPPLY_CP_NONE; chg->thermal_status = TEMP_BELOW_RANGE; + chg->batt_temp_irq_enabled = false; chg->dr_mode = DUAL_ROLE_PROP_MODE_NONE; chg->typec_irq_en = true; @@ -7630,6 +9101,9 @@ int smblib_deinit(struct smb_charger *chg) cancel_delayed_work_sync(&chg->bb_removal_work); cancel_delayed_work_sync(&chg->lpd_ra_open_work); cancel_delayed_work_sync(&chg->lpd_detach_work); + cancel_delayed_work_sync(&chg->raise_qc3_vbus_work); + cancel_delayed_work_sync(&chg->charger_type_recheck); + cancel_delayed_work_sync(&chg->cc_un_compliant_charge_work); cancel_delayed_work_sync(&chg->thermal_regulation_work); cancel_delayed_work_sync(&chg->usbov_dbc_work); cancel_delayed_work_sync(&chg->role_reversal_check); @@ -7650,3 +9124,14 @@ int smblib_deinit(struct smb_charger *chg) return 0; } + +static int __init early_parse_off_charge_flag(char *p) +{ + if (p) { + if (!strcmp(p, "charger")) + off_charge_flag = true; + } + + return 0; +} +early_param("androidboot.mode", early_parse_off_charge_flag); diff --git a/drivers/power/supply/qcom/smb5-lib.h b/drivers/power/supply/qcom/smb5-lib.h index 05a3458f6636..4cde3798c419 100644 --- a/drivers/power/supply/qcom/smb5-lib.h +++ b/drivers/power/supply/qcom/smb5-lib.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018-2020 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -61,14 +62,25 @@ enum print_reason { #define OTG_DELAY_VOTER "OTG_DELAY_VOTER" #define USBIN_I_VOTER "USBIN_I_VOTER" #define WEAK_CHARGER_VOTER "WEAK_CHARGER_VOTER" +#define OTG_VOTER "OTG_VOTER" #define PL_FCC_LOW_VOTER "PL_FCC_LOW_VOTER" #define WBC_VOTER "WBC_VOTER" #define HW_LIMIT_VOTER "HW_LIMIT_VOTER" +#define CHG_AWAKE_VOTER "CHG_AWAKE_VOTER" +#define DCIN_ADAPTER_VOTER "DCIN_ADAPTER_VOTER" +#define DCIN_LIMIT_VOTER "DCIN_LIMIT_VOTER" #define PL_SMB_EN_VOTER "PL_SMB_EN_VOTER" #define FORCE_RECHARGE_VOTER "FORCE_RECHARGE_VOTER" #define LPD_VOTER "LPD_VOTER" +#define DC_AWAKE_VOTER "DC_AWAKE_VOTER" +#define DC_UV_AWAKE_VOTER "DC_UV_AWAKE_VOTER" +#define CLASSA_QC_FCC_VOTER "CLASSA_QC_FCC_VOTER" +#define QC_A_CP_ICL_MAX_VOTER "QC_A_CP_ICL_MAX_VOTER" +#define JEITA_VOTER "JEITA_VOTER" #define FCC_STEPPER_VOTER "FCC_STEPPER_VOTER" #define SW_THERM_REGULATION_VOTER "SW_THERM_REGULATION_VOTER" +#define LIQUID_DETECTION_VOTER "LIQUID_DETECTION_VOTER" +#define QC2_UNSUPPORTED_VOTER "QC2_UNSUPPORTED_VOTER" #define JEITA_ARB_VOTER "JEITA_ARB_VOTER" #define MOISTURE_VOTER "MOISTURE_VOTER" #define HVDCP2_ICL_VOTER "HVDCP2_ICL_VOTER" @@ -86,10 +98,48 @@ enum print_reason { #define MAIN_FCC_VOTER "MAIN_FCC_VOTER" #define DCIN_AICL_VOTER "DCIN_AICL_VOTER" #define OVERHEAT_LIMIT_VOTER "OVERHEAT_LIMIT_VOTER" +#define PD_VERIFED_VOTER "PD_VERIFED_VOTER" #define BOOST_BACK_STORM_COUNT 3 #define WEAK_CHG_STORM_COUNT 8 +#define VOL_THR_FOR_QC_CLASS_AB 12300000 +#define COMP_FOR_LOW_RESISTANCE_CABLE 100000 +#define QC_CLASS_A_CURRENT_UA 3600000 +#define HVDCP_CLASS_A_MAX_UA 2500000 +#define HVDCP_CLASS_A_FOR_CP_UA 2000000 +#define MAX_PULSE 38 +#define MAX_PLUSE_COUNT_ALLOWED 30 +#define HIGH_NUM_PULSE_THR 12 +#define PD_UNVERIFED_CURRENT 3000000 + +/* thermal micros */ +#define MAX_TEMP_LEVEL 16 +/* percent of ICL compared to base 5V for different PD voltage_min voltage */ +#define PD_6P5V_PERCENT 85 +#define PD_7P5V_PERCENT 75 +#define PD_8P5V_PERCENT 70 +#define PD_9V_PERCENT 65 +#define PD_MICRO_5V 5000000 +#define PD_MICRO_5P9V 5900000 +#define PD_MICRO_6P5V 6500000 +#define PD_MICRO_7P5V 7500000 +#define PD_MICRO_8P5V 8500000 +#define PD_MICRO_9V 9000000 +#define ICL_LIMIT_LEVEL_THR 8 + +#define QC2_UNSUPPORTED_UA 1800000 +/* defined for HVDCP2 */ +#define HVDCP2_CURRENT_UA 1500000 + +/* defined for charger type recheck */ +#define CHARGER_RECHECK_DELAY_MS 30000 +#define TYPE_RECHECK_TIME_5S 5000 +#define TYPE_RECHECK_COUNT 3 + +/* defined for un_compliant Type-C cable */ +#define CC_UN_COMPLIANT_START_DELAY_MS 700 + #define VBAT_TO_VRAW_ADC(v) div_u64((u64)v * 1000000UL, 194637UL) #define ITERM_LIMITS_PMI632_MA 5000 @@ -99,15 +149,31 @@ enum print_reason { #define SDP_100_MA 100000 #define SDP_CURRENT_UA 500000 #define CDP_CURRENT_UA 1500000 -#define DCP_CURRENT_UA 1500000 -#define HVDCP_CURRENT_UA 3000000 +#define DCP_CURRENT_UA 1600000 +#define HVDCP_CURRENT_UA 2800000 #define TYPEC_DEFAULT_CURRENT_UA 900000 #define TYPEC_MEDIUM_CURRENT_UA 1500000 #define TYPEC_HIGH_CURRENT_UA 3000000 #define DCIN_ICL_MIN_UA 100000 -#define DCIN_ICL_MAX_UA 1500000 +#define DCIN_ICL_MAX_UA 1200000 #define DCIN_ICL_STEP_UA 100000 +/*DCIN ICL*/ +#define PSNS_CURRENT_SAMPLE_RATE 1053 +#define PSNS_CURRENT_SAMPLE_RESIS 392 +#define PSNS_COMP_UV_FOR_HIGH_THERMAL 40000 + +/* cutoff voltage threshold */ +#define CUTOFF_VOL_THR 3400000 + +#define RECHARGE_SOC_THR 99 + +enum hvdcp3_type { + HVDCP3_NONE = 0, + HVDCP3_CLASSA_18W, + HVDCP3_CLASSB_27W, +}; + #define ROLE_REVERSAL_DELAY_MS 2000 enum smb_mode { @@ -374,6 +440,8 @@ struct smb_iio { struct iio_channel *die_temp_chan; struct iio_channel *skin_temp_chan; struct iio_channel *smb_temp_chan; + struct iio_channel *hw_version_gpio5; + struct iio_channel *project_gpio6; }; struct smb_charger { @@ -390,6 +458,9 @@ struct smb_charger { int otg_delay_ms; int *weak_chg_icl_ua; bool pd_not_supported; + bool init_once; + bool support_liquid; + bool dynamic_fv_enabled; /* locks */ struct mutex smb_lock; @@ -405,11 +476,17 @@ struct smb_charger { struct power_supply *usb_psy; struct power_supply *dc_psy; struct power_supply *bms_psy; + struct power_supply_desc usb_psy_desc; struct power_supply *usb_main_psy; struct power_supply *usb_port_psy; struct power_supply *wls_psy; + struct power_supply *idtp_psy; + struct power_supply *wip_psy; + struct power_supply *wireless_psy; + struct power_supply *wls_chip_psy; struct power_supply *cp_psy; enum power_supply_type real_charger_type; + enum power_supply_type wireless_charger_type; /* dual role class */ struct dual_role_phy_instance *dual_role; @@ -435,6 +512,7 @@ struct smb_charger { struct votable *fcc_main_votable; struct votable *fv_votable; struct votable *usb_icl_votable; + struct votable *dc_icl_votable; struct votable *awake_votable; struct votable *pl_disable_votable; struct votable *chg_disable_votable; @@ -453,16 +531,22 @@ struct smb_charger { struct work_struct moisture_protection_work; struct work_struct chg_termination_work; struct work_struct dcin_aicl_work; + struct work_struct lpd_disable_chg_work; struct delayed_work ps_change_timeout_work; struct delayed_work clear_hdc_work; struct delayed_work icl_change_work; struct delayed_work pl_enable_work; struct delayed_work uusb_otg_work; struct delayed_work bb_removal_work; + struct delayed_work raise_qc3_vbus_work; struct delayed_work lpd_ra_open_work; struct delayed_work lpd_detach_work; + struct delayed_work charger_type_recheck; + struct delayed_work cc_un_compliant_charge_work; + struct delayed_work reg_work; struct delayed_work thermal_regulation_work; struct delayed_work usbov_dbc_work; + struct delayed_work dc_plug_out_delay_work; struct delayed_work role_reversal_check; struct delayed_work pr_swap_detach_work; struct delayed_work pr_lock_clear_work; @@ -485,10 +569,13 @@ struct smb_charger { int voltage_min_uv; int voltage_max_uv; int pd_active; + int pd_verifed; bool pd_hard_reset; bool pr_lock_in_progress; bool pr_swap_in_progress; bool early_usb_attach; + bool early_dc_attach; + bool batt_temp_irq_enabled; bool ok_to_pd; bool typec_legacy; bool typec_irq_en; @@ -498,13 +585,34 @@ struct smb_charger { int boost_threshold_ua; int system_temp_level; int thermal_levels; + int lpd_levels; + int dc_temp_level; + int dc_thermal_levels; +#ifdef CONFIG_THERMAL + int *thermal_mitigation_dcp; + int *thermal_mitigation_qc2; + int *thermal_mitigation_pd_base; + int *thermal_mitigation_icl; + int *thermal_fcc_qc3_normal; + int *thermal_fcc_qc3_cp; + int *thermal_fcc_qc3_classb_cp; + int *thermal_fcc_pps_cp; + int *thermal_mitigation_dc; + int *lpd_hwversion; + int *thermal_mitigation_epp; + int *thermal_mitigation_bpp_qc3; + int *thermal_mitigation_bpp_qc2; + int *thermal_mitigation_bpp; +#else int *thermal_mitigation; +#endif int dcp_icl_ua; int fake_capacity; int fake_batt_status; bool step_chg_enabled; bool sw_jeita_enabled; bool typec_legacy_use_rp_icl; + bool lpd_enabled; bool is_hdc; bool chg_done; int connector_type; @@ -534,6 +642,7 @@ struct smb_charger { enum lpd_stage lpd_stage; bool lpd_disabled; enum lpd_reason lpd_reason; + bool lpd_status; bool fcc_stepper_enable; int die_temp; int smb_temp; @@ -541,6 +650,7 @@ struct smb_charger { int connector_temp; int thermal_status; int main_fcc_max; + bool report_usb_absent; u32 jeita_soft_thlds[2]; u32 jeita_soft_hys_thlds[2]; int jeita_soft_fcc[2]; @@ -577,6 +687,8 @@ struct smb_charger { int qc2_max_pulses; enum qc2_non_comp_voltage qc2_unsupported_voltage; bool dbc_usbov; + bool fake_usb_insertion; + bool qc2_unsupported; /* extcon for VBUS / ID notification to USB for uUSB */ struct extcon_dev *extcon; @@ -590,6 +702,13 @@ struct smb_charger { int die_health; int connector_health; + /* raise qc3 vbus flag */ + bool qc_class_ab; + bool is_qc_class_a; + bool is_qc_class_b; + bool raise_vbus_to_detect; + bool detect_low_power_qc3_charger; + bool high_vbus_detected; /* flash */ u32 flash_derating_soc; @@ -603,6 +722,32 @@ struct smb_charger { int dcin_uv_count; ktime_t dcin_uv_last_time; int last_wls_vout; + int wireless_vout; + int flag_dc_present; + int power_good_en; + int fake_dc_on; + int fake_dc_flag; + int last_batt_stat; + /* charger type recheck */ + int recheck_charger; + int precheck_charger_type; + /* workarounds */ + bool cc_un_compliant_detected; + bool snk_debug_acc_detected; + bool support_wireless; +}; + +enum quick_charge_type { + QUICK_CHARGE_NORMAL = 0, + QUICK_CHARGE_FAST, + QUICK_CHARGE_FLASH, + QUICK_CHARGE_TURBE, + QUICK_CHARGE_MAX, +}; + +struct quick_charge { + enum power_supply_type adap_type; + enum quick_charge_type adap_cap; }; int smblib_read(struct smb_charger *chg, u16 addr, u8 *val); @@ -621,6 +766,8 @@ int smblib_set_charge_param(struct smb_charger *chg, int smblib_set_usb_suspend(struct smb_charger *chg, bool suspend); int smblib_set_dc_suspend(struct smb_charger *chg, bool suspend); +int smblib_change_psns_to_curr(struct smb_charger *chg, int uv); + int smblib_mapping_soc_from_field_value(struct smb_chg_param *param, int val_u, u8 *val_raw); int smblib_mapping_cc_delta_to_field_value(struct smb_chg_param *param, @@ -642,6 +789,7 @@ int smblib_vconn_regulator_disable(struct regulator_dev *rdev); int smblib_vconn_regulator_is_enabled(struct regulator_dev *rdev); irqreturn_t default_irq_handler(int irq, void *data); +irqreturn_t dcin_uv_handler(int irq, void *data); irqreturn_t smb_en_irq_handler(int irq, void *data); irqreturn_t chg_state_change_irq_handler(int irq, void *data); irqreturn_t batt_temp_changed_irq_handler(int irq, void *data); @@ -680,6 +828,8 @@ int smblib_get_prop_system_temp_level(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_system_temp_level_max(struct smb_charger *chg, union power_supply_propval *val); +int smblib_get_prop_dc_temp_level(struct smb_charger *chg, + union power_supply_propval *val); int smblib_get_prop_input_current_limited(struct smb_charger *chg, union power_supply_propval *val); int smblib_get_prop_batt_iterm(struct smb_charger *chg, @@ -692,6 +842,8 @@ int smblib_set_prop_batt_status(struct smb_charger *chg, const union power_supply_propval *val); int smblib_set_prop_system_temp_level(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_set_prop_dc_temp_level(struct smb_charger *chg, + const union power_supply_propval *val); int smblib_set_prop_input_current_limited(struct smb_charger *chg, const union power_supply_propval *val); @@ -711,6 +863,8 @@ int smblib_get_prop_voltage_wls_output(struct smb_charger *chg, union power_supply_propval *val); int smblib_set_prop_voltage_wls_output(struct smb_charger *chg, const union power_supply_propval *val); +int smblib_get_prop_wireless_version(struct smb_charger *chg, + union power_supply_propval *val); int smblib_set_prop_dc_reset(struct smb_charger *chg); int smblib_get_prop_usb_present(struct smb_charger *chg, union power_supply_propval *val); @@ -802,6 +956,23 @@ int smblib_configure_hvdcp_apsd(struct smb_charger *chg, bool enable); int smblib_icl_override(struct smb_charger *chg, enum icl_override_mode mode); enum alarmtimer_restart smblib_lpd_recheck_timer(struct alarm *alarm, ktime_t time); +int smblib_set_prop_wireless_wakelock(struct smb_charger *chg, + const union power_supply_propval *val); + +int smblib_set_prop_type_recheck(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_get_prop_type_recheck(struct smb_charger *chg, + union power_supply_propval *val); +int smblib_get_quick_charge_type(struct smb_charger *chg); +int smblib_set_wirless_cp_enable(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_set_wirless_power_good_enable(struct smb_charger *chg, + const union power_supply_propval *val); +int smblib_get_prop_liquid_status(struct smb_charger *chg, + union power_supply_propval *val); + +bool smblib_support_liquid_feature(struct smb_charger *chg); + int smblib_toggle_smb_en(struct smb_charger *chg, int toggle); void smblib_hvdcp_detect_enable(struct smb_charger *chg, bool enable); void smblib_hvdcp_exit_config(struct smb_charger *chg); diff --git a/drivers/power/supply/qcom/smb5-reg.h b/drivers/power/supply/qcom/smb5-reg.h index 454cc490d3f0..0a878f73bb69 100644 --- a/drivers/power/supply/qcom/smb5-reg.h +++ b/drivers/power/supply/qcom/smb5-reg.h @@ -1,4 +1,5 @@ /* Copyright (c) 2018-2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -316,6 +317,10 @@ enum { #define USBIN_5V_AICL_THRESHOLD_REG (USBIN_BASE + 0x81) #define USBIN_CONT_AICL_THRESHOLD_REG (USBIN_BASE + 0x84) + +#define TYPE_C_CFG_REG (USBIN_BASE + 0x58) +#define APSD_START_ON_CC_BIT BIT(7) + /******************************** * DCIN Peripheral Registers * ********************************/ @@ -326,6 +331,12 @@ enum { #define DCIN_CMD_IL_REG (DCIN_BASE + 0x40) #define DCIN_SUSPEND_BIT BIT(0) #define DCIN_EN_OVERRIDE_BIT BIT(1) +#define DCIN_EN_BIT BIT(2) + +#define DCIN_CMD_PULLDOWN_REG (DCIN_BASE + 0x45) +#define DCIN_PULLDOWN_EN_BIT BIT(0) +#define DCIN_MID_PULLDOWN_BIT BIT(1) + #define DCIN_EN_MASK GENMASK(2, 1) #define DCIN_CMD_PON_REG (DCIN_BASE + 0x45) @@ -348,6 +359,9 @@ enum { #define SNK_RP_3P0_BIT BIT(1) #define SNK_RP_SHORT_BIT BIT(0) +#define TYPE_C_SNK_DEBUG_ACC_STATUS_REG (TYPEC_BASE + 0x07) +#define SNK_DEBUG_ACC_RPSTD_PRSTD_BIT BIT(0) + #define TYPE_C_SRC_STATUS_REG (TYPEC_BASE + 0x08) #define DETECTED_SNK_TYPE_MASK GENMASK(4, 0) #define SRC_HIGH_BATT_BIT BIT(5) @@ -399,6 +413,10 @@ enum { #define TYPEC_CCOUT_VALUE_BIT BIT(1) #define TYPEC_CCOUT_SRC_BIT BIT(0) +#define TYPE_C_DEBUG_ACC_SNK_CFG (TYPEC_BASE + 0x4A) +#define TYPEC_DEBUG_ACC_SNK_SEL_ICL BIT(2) +#define TYPEC_DEBUG_ACC_SNK_DIS_AICL BIT(3) + #define DEBUG_ACCESS_SRC_CFG_REG (TYPEC_BASE + 0x4C) #define EN_UNORIENTED_DEBUG_ACCESS_SRC_BIT BIT(0) @@ -514,6 +532,7 @@ enum { #define WATCHDOG_TRIGGER_AFP_EN_BIT BIT(7) #define BARK_WDOG_INT_EN_BIT BIT(6) #define WDOG_TIMER_EN_ON_PLUGIN_BIT BIT(1) +#define WDOG_TIMER_EN_BIT BIT(0) #define SNARL_BARK_BITE_WD_CFG_REG (MISC_BASE + 0x53) #define BITE_WDOG_DISABLE_CHARGING_CFG_BIT BIT(7) diff --git a/drivers/power/supply/qcom/step-chg-jeita.c b/drivers/power/supply/qcom/step-chg-jeita.c index ab8eeb897745..3acb3aa22254 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.c +++ b/drivers/power/supply/qcom/step-chg-jeita.c @@ -1,4 +1,5 @@ /* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -22,6 +23,7 @@ #define STEP_CHG_VOTER "STEP_CHG_VOTER" #define JEITA_VOTER "JEITA_VOTER" +#define DYNAMIC_FV_VOTER "DYNAMIC_FV_VOTER" #define is_between(left, right, value) \ (((left) >= (right) && (left) >= (value) \ @@ -44,16 +46,24 @@ struct jeita_fv_cfg { struct range_data fv_cfg[MAX_STEP_CHG_ENTRIES]; }; +struct dynamic_fv_cfg { + char *prop_name; + struct range_data fv_cfg[MAX_STEP_CHG_ENTRIES]; +}; + struct step_chg_info { struct device *dev; ktime_t step_last_update_time; ktime_t jeita_last_update_time; + ktime_t dynamic_fv_last_update_time; bool step_chg_enable; bool sw_jeita_enable; + bool dynamic_fv_enable; bool jeita_arb_en; bool config_is_read; bool step_chg_cfg_valid; bool sw_jeita_cfg_valid; + bool dynamic_fv_cfg_valid; bool soc_based_step_chg; bool ocv_based_step_chg; bool vbat_avg_based_step_chg; @@ -61,16 +71,19 @@ struct step_chg_info { bool taper_fcc; int jeita_fcc_index; int jeita_fv_index; + int dynamic_fv_index; int step_index; int get_config_retry_count; struct step_chg_cfg *step_chg_config; struct jeita_fcc_cfg *jeita_fcc_config; struct jeita_fv_cfg *jeita_fv_config; + struct dynamic_fv_cfg *dynamic_fv_config; struct votable *fcc_votable; struct votable *fv_votable; struct votable *usb_icl_votable; + struct votable *dc_suspend_votable; struct wakeup_source *step_chg_ws; struct power_supply *batt_psy; struct power_supply *bms_psy; @@ -360,6 +373,17 @@ static int get_step_chg_jeita_setting_from_profile(struct step_chg_info *chip) chip->sw_jeita_cfg_valid = false; } + chip->dynamic_fv_cfg_valid = true; + rc = read_range_data_from_node(profile_node, + "qcom,dynamic-fv-ranges", + chip->dynamic_fv_config->fv_cfg, + BATT_HOT_DECIDEGREE_MAX, max_fv_uv); + if (rc < 0) { + pr_debug("Read qcom,dynamic-fv-ranges failed from battery profile, rc=%d\n", + rc); + chip->dynamic_fv_cfg_valid = false; + } + return rc; } @@ -400,7 +424,11 @@ static void get_config_work(struct work_struct *work) chip->jeita_fv_config->fv_cfg[i].low_threshold, chip->jeita_fv_config->fv_cfg[i].high_threshold, chip->jeita_fv_config->fv_cfg[i].value); - + for (i = 0; i < MAX_STEP_CHG_ENTRIES; i++) + pr_info("dynamic-fv-cfg: %d(count) ~ %d(count), %duV\n", + chip->dynamic_fv_config->fv_cfg[i].low_threshold, + chip->dynamic_fv_config->fv_cfg[i].high_threshold, + chip->dynamic_fv_config->fv_cfg[i].value); return; reschedule: @@ -417,6 +445,14 @@ static int get_val(struct range_data *range, int hysteresis, int current_index, *new_index = -EINVAL; + /* + * As battery temperature may be below 0, range.xxx is a unsigned int, but battery + * temperature is a signed int, so cannot compare them when battery temp is below 0, + * we treat it as 0 degree when the parameter threshold(battery temp) is below 0. + */ + if (threshold < 0) + threshold = 0; + /* * If the threshold is lesser than the minimum allowed range, * return -ENODATA. @@ -456,6 +492,14 @@ static int get_val(struct range_data *range, int hysteresis, int current_index, *val = range[*new_index].value; } + if (threshold < range[0].low_threshold) { + *new_index = 0; + *val = range[*new_index].value; + } else if (threshold > range[MAX_STEP_CHG_ENTRIES - 1].low_threshold) { + *new_index = MAX_STEP_CHG_ENTRIES - 1; + *val = range[*new_index].value; + } + /* * If we don't have a current_index return this * newfound value. There is no hysterisis from out of range @@ -614,7 +658,86 @@ static int handle_step_chg_config(struct step_chg_info *chip) return 0; } -#define JEITA_SUSPEND_HYST_UV 50000 +static int handle_dynamic_fv(struct step_chg_info *chip) +{ + union power_supply_propval pval = {0, }; + int rc = 0, fv_uv, cycle_count; + u64 elapsed_us; + int batt_vol = 0; + + rc = power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED, &pval); + if (rc < 0) + chip->dynamic_fv_enable = 0; + else + chip->dynamic_fv_enable = pval.intval; + + if (!chip->dynamic_fv_enable || !chip->dynamic_fv_cfg_valid) { + /*need recovery some setting*/ + if (chip->fv_votable) + vote(chip->fv_votable, DYNAMIC_FV_VOTER, false, 0); + return 0; + } + + elapsed_us = ktime_us_delta(ktime_get(), chip->dynamic_fv_last_update_time); + /* skip processing, event too early */ + if (elapsed_us < STEP_CHG_HYSTERISIS_DELAY_US) + return 0; + + rc = power_supply_get_property(chip->bms_psy, + POWER_SUPPLY_PROP_CYCLE_COUNT, &pval); + if (rc < 0) { + pr_err("Couldn't read %s property rc=%d\n", + chip->dynamic_fv_config->prop_name, rc); + return rc; + } + cycle_count = pval.intval; + + rc = get_val(chip->dynamic_fv_config->fv_cfg, + 0, + chip->dynamic_fv_index, + cycle_count, + &chip->dynamic_fv_index, + &fv_uv); + if (rc < 0) { + /* remove the vote if no step-based fv is found */ + if (chip->fv_votable) + vote(chip->fv_votable, DYNAMIC_FV_VOTER, false, 0); + goto update_time; + } + + power_supply_get_property(chip->batt_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); + batt_vol = pval.intval; + if (batt_vol >= fv_uv) { + goto update_time; + } + + chip->fv_votable = find_votable("FV"); + if (!chip->fv_votable) + goto update_time; + + vote(chip->fv_votable, DYNAMIC_FV_VOTER, true, fv_uv); + + /*set battery full voltage to FLOAT VOLTAGE - 10mV*/ + pval.intval = fv_uv - 10000; + rc = power_supply_set_property(chip->bms_psy, + POWER_SUPPLY_PROP_CONSTANT_CHARGE_VOLTAGE, &pval); + if (rc < 0) { + pr_err("Couldn't set CONSTANT VOLTAGE property rc=%d\n", rc); + return rc; + } + + pr_debug("%s:cycle_count:%d,Batt_full:%d,fv:%d,\n", + __func__, cycle_count, pval.intval, fv_uv); + +update_time: + chip->dynamic_fv_last_update_time = ktime_get(); + return 0; +} + +/* set JEITA_SUSPEND_HYST_UV to 70mV to avoid recharge frequently when jeita warm */ +#define JEITA_SUSPEND_HYST_UV 70000 static int handle_jeita(struct step_chg_info *chip) { union power_supply_propval pval = {0, }; @@ -635,6 +758,8 @@ static int handle_jeita(struct step_chg_info *chip) vote(chip->fv_votable, JEITA_VOTER, false, 0); if (chip->usb_icl_votable) vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); + if (chip->dc_suspend_votable) + vote(chip->dc_suspend_votable, JEITA_VOTER, 0, 0); return 0; } @@ -692,6 +817,12 @@ static int handle_jeita(struct step_chg_info *chip) if (!chip->usb_icl_votable) goto set_jeita_fv; + if (!chip->dc_suspend_votable) + chip->dc_suspend_votable = find_votable("DC_SUSPEND"); + + if (!chip->dc_suspend_votable) + goto set_jeita_fv; + /* * If JEITA float voltage is same as max-vfloat of battery then * skip any further VBAT specific checks. @@ -700,6 +831,7 @@ static int handle_jeita(struct step_chg_info *chip) POWER_SUPPLY_PROP_VOLTAGE_MAX, &pval); if (rc || (pval.intval == fv_uv)) { vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); + vote(chip->dc_suspend_votable, JEITA_VOTER, 0, 0); goto set_jeita_fv; } @@ -707,13 +839,17 @@ static int handle_jeita(struct step_chg_info *chip) * Suspend USB input path if battery voltage is above * JEITA VFLOAT threshold. */ - if (chip->jeita_arb_en && fv_uv > 0) { + /* if (chip->jeita_arb_en && fv_uv > 0) { */ + if (fv_uv > 0) { rc = power_supply_get_property(chip->batt_psy, POWER_SUPPLY_PROP_VOLTAGE_NOW, &pval); - if (!rc && (pval.intval > fv_uv)) + if (!rc && (pval.intval > fv_uv)) { vote(chip->usb_icl_votable, JEITA_VOTER, true, 0); - else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV)) + vote(chip->dc_suspend_votable, JEITA_VOTER, 1, 0); + } else if (pval.intval < (fv_uv - JEITA_SUSPEND_HYST_UV)) { vote(chip->usb_icl_votable, JEITA_VOTER, false, 0); + vote(chip->dc_suspend_votable, JEITA_VOTER, 0, 0); + } } set_jeita_fv: @@ -744,6 +880,7 @@ static int handle_battery_insertion(struct step_chg_info *chip) if (chip->batt_missing) { chip->step_chg_cfg_valid = false; chip->sw_jeita_cfg_valid = false; + chip->dynamic_fv_cfg_valid = false; chip->get_config_retry_count = 0; } else { /* @@ -775,6 +912,10 @@ static void status_change_work(struct work_struct *work) if (rc < 0) pr_err("Couldn't handle sw jeita rc = %d\n", rc); + rc = handle_dynamic_fv(chip); + if (rc < 0) + pr_err("Couldn't handle sw dynamic fv rc = %d\n", rc); + rc = handle_step_chg_config(chip); if (rc < 0) pr_err("Couldn't handle step rc = %d\n", rc); @@ -860,6 +1001,7 @@ int qcom_step_chg_init(struct device *dev, chip->step_index = -EINVAL; chip->jeita_fcc_index = -EINVAL; chip->jeita_fv_index = -EINVAL; + chip->dynamic_fv_index = -EINVAL; chip->step_chg_config = devm_kzalloc(dev, sizeof(struct step_chg_cfg), GFP_KERNEL); @@ -874,15 +1016,18 @@ int qcom_step_chg_init(struct device *dev, sizeof(struct jeita_fcc_cfg), GFP_KERNEL); chip->jeita_fv_config = devm_kzalloc(dev, sizeof(struct jeita_fv_cfg), GFP_KERNEL); - if (!chip->jeita_fcc_config || !chip->jeita_fv_config) + chip->dynamic_fv_config = devm_kzalloc(dev, + sizeof(struct dynamic_fv_cfg), GFP_KERNEL); + if (!chip->jeita_fcc_config || !chip->jeita_fv_config || !chip->dynamic_fv_config) return -ENOMEM; chip->jeita_fcc_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP; chip->jeita_fcc_config->param.prop_name = "BATT_TEMP"; - chip->jeita_fcc_config->param.hysteresis = 10; + chip->jeita_fcc_config->param.hysteresis = 5; chip->jeita_fv_config->param.psy_prop = POWER_SUPPLY_PROP_TEMP; chip->jeita_fv_config->param.prop_name = "BATT_TEMP"; - chip->jeita_fv_config->param.hysteresis = 10; + chip->jeita_fv_config->param.hysteresis = 5; + chip->dynamic_fv_config->prop_name = "BATT_CYCLE_COUNT"; INIT_DELAYED_WORK(&chip->status_change_work, status_change_work); INIT_DELAYED_WORK(&chip->get_config_work, get_config_work); diff --git a/drivers/power/supply/qcom/step-chg-jeita.h b/drivers/power/supply/qcom/step-chg-jeita.h index 26e74ed484e9..8032c93d5de6 100644 --- a/drivers/power/supply/qcom/step-chg-jeita.h +++ b/drivers/power/supply/qcom/step-chg-jeita.h @@ -1,4 +1,5 @@ /* Copyright (c) 2017-2019 The Linux Foundation. All rights reserved. + * Copyright (C) 2019 XiaoMi, Inc. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -13,7 +14,7 @@ #ifndef __STEP_CHG_H__ #define __STEP_CHG_H__ -#define MAX_STEP_CHG_ENTRIES 8 +#define MAX_STEP_CHG_ENTRIES 5 struct step_chg_jeita_param { u32 psy_prop; diff --git a/drivers/pwm/pwm-qti-lpg.c b/drivers/pwm/pwm-qti-lpg.c index 2b01b5b86b4a..8187d3e4dae4 100644 --- a/drivers/pwm/pwm-qti-lpg.c +++ b/drivers/pwm/pwm-qti-lpg.c @@ -172,6 +172,10 @@ struct qpnp_lpg_lut { struct mutex lock; u32 reg_base; u32 *pattern; /* patterns in percentage */ + bool pattern_switch; + u32 pattern_length; + u32 *pattern_camera; + u32 pattern_camera_length; }; struct qpnp_lpg_channel { @@ -382,6 +386,58 @@ static struct qpnp_lpg_channel *pwm_dev_to_qpnp_lpg(struct pwm_chip *pwm_chip, return &chip->lpgs[hw_idx]; } +void qpnp_lpg_ramp_step_ms_set(struct pwm_device *pwm, u16 step_ms) +{ + struct qpnp_lpg_channel *channel; + + if (pwm != NULL) + channel = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + + if (channel != NULL) + channel->ramp_config.step_ms = step_ms; +} +EXPORT_SYMBOL(qpnp_lpg_ramp_step_ms_set); + +int qpnp_lpg_ramp_step_ms_get(struct pwm_device *pwm) +{ + struct qpnp_lpg_channel *channel; + + if (pwm != NULL) + channel = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + + if (channel != NULL) + return channel->ramp_config.step_ms; + + return 0; +} +EXPORT_SYMBOL(qpnp_lpg_ramp_step_ms_get); + +void qpnp_lpg_pause_lo_count_set(struct pwm_device *pwm, u8 pause_lo_count) +{ + struct qpnp_lpg_channel *channel; + + if (pwm != NULL) + channel = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + + if (channel != NULL) + channel->ramp_config.pause_lo_count = pause_lo_count; +} +EXPORT_SYMBOL(qpnp_lpg_pause_lo_count_set); + +u8 qpnp_lpg_pause_lo_count_get(struct pwm_device *pwm) +{ + struct qpnp_lpg_channel *channel; + + if (pwm != NULL) + channel = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + + if (channel != NULL) + return channel->ramp_config.pause_lo_count; + + return 0; +} +EXPORT_SYMBOL(qpnp_lpg_pause_lo_count_get); + static int __find_index_in_array(int member, const int array[], int length) { int i; @@ -725,6 +781,84 @@ static int qpnp_lpg_set_ramp_config(struct qpnp_lpg_channel *lpg) return rc; } +u8 qpnp_lpg_switch_lut_pattern(struct pwm_device *pwm, int index) +{ + struct qpnp_lpg_channel *channel; + struct qpnp_lpg_lut *lut; + + if (pwm != NULL) + channel = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + + if (channel != NULL) + lut = channel->chip->lut; + + if (lut == NULL) { + pr_err("lut is NULL\n"); + return -1; + } + + if (!lut->pattern_switch) { + pr_err("lut pattern switch disabled\n"); + return -1; + } + + if (index < 0) { + pr_err("invalid index:%d\n", index); + return -1; + } + + if (index == 0) { + channel->ramp_config.lo_idx = 0; + qpnp_lpg_set_lut_pattern(channel, lut->pattern, lut->pattern_length); + channel->ramp_config.hi_idx = lut->pattern_length - 1; + } else { + channel->ramp_config.lo_idx = 0; + qpnp_lpg_set_lut_pattern(channel, lut->pattern_camera, lut->pattern_camera_length); + channel->ramp_config.hi_idx = lut->pattern_camera_length - 1; + } + + return 0; +} +EXPORT_SYMBOL(qpnp_lpg_switch_lut_pattern); + +u8 qpnp_lpg_lo_idx_get(struct pwm_device *pwm) +{ + struct qpnp_lpg_channel *channel; + + if (pwm != NULL) + channel = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + + return channel->ramp_config.lo_idx; +} +EXPORT_SYMBOL(qpnp_lpg_lo_idx_get); + +u8 qpnp_lpg_lo_idx_set(struct pwm_device *pwm, int lo_idx) +{ + struct qpnp_lpg_channel *channel; + struct qpnp_lpg_lut *lut; + + if (pwm != NULL) + channel = pwm_dev_to_qpnp_lpg(pwm->chip, pwm); + + if (channel != NULL) + lut = channel->chip->lut; + + if (lut == NULL) { + pr_err("lut is NULL\n"); + return -1; + } + + if (lo_idx < 0 || lo_idx > lut->pattern_length) { + pr_err("invalid lo_idx:%d\n", lo_idx); + return -1; + } + + channel->ramp_config.lo_idx = lo_idx; + + return 0; +} +EXPORT_SYMBOL(qpnp_lpg_lo_idx_set); + static void __qpnp_lpg_calc_pwm_period(u64 period_ns, struct lpg_pwm_config *pwm_config) { @@ -1438,6 +1572,8 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) } length = rc; + chip->lut->pattern_length = rc; + if (length > max_count) { dev_err(chip->dev, "qcom,lut-patterns length %d exceed max %d\n", length, max_count); @@ -1457,6 +1593,41 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) return rc; } + chip->lut->pattern_switch = of_property_read_bool(chip->dev->of_node, + "qcom,lut-pattern-switch"); + pr_info("lut pattern switch %s\n", + chip->lut->pattern_switch ? "enable" : "disable"); + + if (chip->lut->pattern_switch) { + rc = of_property_count_elems_of_size(chip->dev->of_node, + "qcom,lut-patterns-camera", sizeof(u32)); + if (rc < 0) { + dev_err(chip->dev, "Read qcom,lut-patterns-camera failed, rc=%d\n", + rc); + return rc; + } + + chip->lut->pattern_camera_length = rc; + if (chip->lut->pattern_camera_length > LPG_LUT_COUNT_MAX) { + dev_err(chip->dev, "qcom,lut-patterns-camera length %d exceed max %d\n", + length, LPG_LUT_COUNT_MAX); + return -EINVAL; + } + + chip->lut->pattern_camera = devm_kcalloc(chip->dev, LPG_LUT_COUNT_MAX, + sizeof(*chip->lut->pattern_camera), GFP_KERNEL); + if (!chip->lut->pattern_camera) + return -ENOMEM; + + rc = of_property_read_u32_array(chip->dev->of_node, "qcom,lut-patterns-camera", + chip->lut->pattern_camera, chip->lut->pattern_camera_length); + if (rc < 0) { + dev_err(chip->dev, "Get qcom,lut-patterns-camera failed, rc=%d\n", + rc); + return rc; + } + } + if (of_get_available_child_count(chip->dev->of_node) == 0) { dev_err(chip->dev, "No ramp configuration for any LPG\n"); return -EINVAL; @@ -1544,6 +1715,12 @@ static int qpnp_lpg_parse_dt(struct qpnp_lpg_chip *chip) if (chip->use_sdam) continue; + if (chip->lut->pattern_switch) { + lpg->max_pattern_length = + chip->lut->pattern_length > chip->lut->pattern_camera_length ? \ + chip->lut->pattern_length : chip->lut->pattern_camera_length; + } + rc = of_property_read_u32(child, "qcom,ramp-pause-hi-count", &tmp); if (rc < 0) diff --git a/drivers/rpmsg/qcom_glink_native.c b/drivers/rpmsg/qcom_glink_native.c index ee66de996d33..b29eb8a7662a 100644 --- a/drivers/rpmsg/qcom_glink_native.c +++ b/drivers/rpmsg/qcom_glink_native.c @@ -116,6 +116,7 @@ struct glink_core_rx_intent { * @rx_pipe: pipe object for receive FIFO * @tx_pipe: pipe object for transmit FIFO * @irq: IRQ for signaling incoming events + * @irq_name: name registered for IRQ * @kworker: kworker to handle rx_done work * @task: kthread running @kworker * @rx_work: worker for handling received control messages @@ -140,6 +141,7 @@ struct qcom_glink { struct qcom_glink_pipe *tx_pipe; int irq; + const char *irq_name; struct kthread_worker kworker; struct task_struct *task; @@ -1912,11 +1914,14 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, struct qcom_glink_pipe *tx, bool intentless) { + static const char *unknown_irq = "unknown"; + static const char *irq_prefix = "glink-native-"; struct qcom_glink *glink; u32 *arr; int size; int irq; int ret; + const char *irq_src; glink = devm_kzalloc(dev, sizeof(*glink), GFP_KERNEL); if (!glink) @@ -1945,6 +1950,15 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, if (ret < 0) glink->name = dev->of_node->name; + irq_src = glink->name; + if (irq_src == NULL) + irq_src = unknown_irq; + size = strlen(irq_prefix) + strlen(irq_src) + 1; + glink->irq_name = devm_kzalloc(dev, size, GFP_KERNEL); + if (!glink->irq_name) + return ERR_PTR(-ENOMEM); + snprintf((char *)glink->irq_name, size, "%s%s", irq_prefix, irq_src); + glink->mbox_client.dev = dev; glink->mbox_client.knows_txdone = true; glink->mbox_chan = mbox_request_channel(&glink->mbox_client, 0); @@ -1972,14 +1986,17 @@ struct qcom_glink *qcom_glink_native_probe(struct device *dev, irq = of_irq_get(dev->of_node, 0); ret = devm_request_irq(dev, irq, qcom_glink_native_intr, - IRQF_NO_SUSPEND | IRQF_SHARED, - "glink-native", glink); + IRQF_SHARED, + glink->irq_name, glink); if (ret) { dev_err(dev, "failed to request IRQ\n"); goto unregister; } glink->irq = irq; + ret = enable_irq_wake(glink->irq); + if (ret) + dev_err(dev, "failed to set irq wake\n"); size = of_property_count_u32_elems(dev->of_node, "cpu-affinity"); if (size > 0) { diff --git a/drivers/scsi/ufs/ufs-qcom.c b/drivers/scsi/ufs/ufs-qcom.c index a919d52cf97c..35dde5dbe26b 100644 --- a/drivers/scsi/ufs/ufs-qcom.c +++ b/drivers/scsi/ufs/ufs-qcom.c @@ -35,8 +35,6 @@ #define MAX_PROP_SIZE 32 #define VDDP_REF_CLK_MIN_UV 1200000 #define VDDP_REF_CLK_MAX_UV 1200000 -/* TODO: further tuning for this parameter may be required */ -#define UFS_QCOM_PM_QOS_UNVOTE_TIMEOUT_US (10000) /* microseconds */ #define UFS_QCOM_DEFAULT_DBG_PRINT_EN \ (UFS_QCOM_DBG_PRINT_REGS_EN | UFS_QCOM_DBG_PRINT_TEST_BUS_EN) @@ -1387,9 +1385,9 @@ static void ufs_qcom_dev_ref_clk_ctrl(struct ufs_qcom_host *host, bool enable) if (enable) { if (host->hba->dev_info.quirks & UFS_DEVICE_QUIRK_WAIT_AFTER_REF_CLK_UNGATE) - usleep_range(50, 60); + usleep_range(960, 970); else - udelay(1); + usleep_range(200, 210); } host->is_dev_ref_clk_enabled = enable; @@ -1408,6 +1406,9 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, int ret = 0; int res = 0; + hba->ufs_stats.clk_hold.ctx = PWR_CHG_NOTIFY; + ufshcd_hold(hba, false); + if (!dev_req_params) { pr_err("%s: incoming dev_req_params is NULL\n", __func__); ret = -EINVAL; @@ -1498,6 +1499,8 @@ static int ufs_qcom_pwr_change_notify(struct ufs_hba *hba, break; } out: + hba->ufs_stats.clk_rel.ctx = PWR_CHG_NOTIFY; + ufshcd_release(hba, false); return ret; } @@ -1785,8 +1788,7 @@ static void ufs_qcom_pm_qos_unvote_work(struct work_struct *work) group->state = PM_QOS_UNVOTED; spin_unlock_irqrestore(host->hba->host->host_lock, flags); - pm_qos_update_request_timeout(&group->req, - group->latency_us, UFS_QCOM_PM_QOS_UNVOTE_TIMEOUT_US); + pm_qos_update_request(&group->req, PM_QOS_DEFAULT_VALUE); } static ssize_t ufs_qcom_pm_qos_enable_show(struct device *dev, @@ -1954,9 +1956,8 @@ static int ufs_qcom_pm_qos_init(struct ufs_qcom_host *host) if (ret) goto free_groups; - host->pm_qos.groups[i].req.type = PM_QOS_REQ_AFFINE_CORES; - host->pm_qos.groups[i].req.cpus_affine = - host->pm_qos.groups[i].mask; + host->pm_qos.groups[i].req.type = PM_QOS_REQ_AFFINE_IRQ; + host->pm_qos.groups[i].req.irq = host->hba->irq; host->pm_qos.groups[i].state = PM_QOS_UNVOTED; host->pm_qos.groups[i].active_reqs = 0; host->pm_qos.groups[i].host = host; diff --git a/drivers/scsi/ufs/ufs_quirks.h b/drivers/scsi/ufs/ufs_quirks.h index acf36c443ea6..1e46ae293b3d 100644 --- a/drivers/scsi/ufs/ufs_quirks.h +++ b/drivers/scsi/ufs/ufs_quirks.h @@ -24,6 +24,7 @@ #define UFS_VENDOR_TOSHIBA 0x198 #define UFS_VENDOR_SAMSUNG 0x1CE #define UFS_VENDOR_SKHYNIX 0x1AD +#define UFS_VENDOR_SANDISK 0x0145 /** * ufs_dev_fix - ufs device quirk info diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index 6507f3a25cdb..55b3b78901b5 100644 --- a/drivers/scsi/ufs/ufshcd.c +++ b/drivers/scsi/ufs/ufshcd.c @@ -210,6 +210,8 @@ static void ufshcd_update_uic_error_cnt(struct ufs_hba *hba, u32 reg, int type) /* UIC command timeout, unit: ms */ #define UIC_CMD_TIMEOUT 500 +#define UIC_PWR_CTRL_TIMEOUT 3000 + /* NOP OUT retries waiting for NOP IN response */ #define NOP_OUT_RETRIES 10 /* Timeout after 30 msecs if NOP OUT hangs without response */ @@ -218,7 +220,7 @@ static void ufshcd_update_uic_error_cnt(struct ufs_hba *hba, u32 reg, int type) /* Query request retries */ #define QUERY_REQ_RETRIES 3 /* Query request timeout */ -#define QUERY_REQ_TIMEOUT 1500 /* 1.5 seconds */ +#define QUERY_REQ_TIMEOUT 3000 /* 3.0 seconds */ /* Task management command timeout */ #define TM_CMD_TIMEOUT 100 /* msecs */ @@ -421,6 +423,8 @@ static struct ufs_dev_fix ufs_fixups[] = { UFS_DEVICE_QUIRK_HOST_PA_SAVECONFIGTIME), UFS_FIX(UFS_VENDOR_SKHYNIX, UFS_ANY_MODEL, UFS_DEVICE_QUIRK_WAIT_AFTER_REF_CLK_UNGATE), + UFS_FIX(UFS_VENDOR_SANDISK, UFS_ANY_MODEL, + UFS_DEVICE_QUIRK_WAIT_AFTER_REF_CLK_UNGATE), UFS_FIX(UFS_VENDOR_SKHYNIX, "hB8aL1", UFS_DEVICE_QUIRK_HS_G1_TO_HS_G3_SWITCH), UFS_FIX(UFS_VENDOR_SKHYNIX, "hC8aL1", @@ -5135,7 +5139,7 @@ static int ufshcd_uic_pwr_ctrl(struct ufs_hba *hba, struct uic_command *cmd) more_wait: if (!wait_for_completion_timeout(hba->uic_async_done, - msecs_to_jiffies(UIC_CMD_TIMEOUT))) { + msecs_to_jiffies(UIC_PWR_CTRL_TIMEOUT))) { u32 intr_status = 0; s64 ts_since_last_intr; @@ -11137,6 +11141,8 @@ int ufshcd_init(struct ufs_hba *hba, void __iomem *mmio_base, unsigned int irq) ufshcd_add_sysfs_nodes(hba); + device_enable_async_suspend(dev); + return 0; out_remove_scsi_host: diff --git a/drivers/scsi/ufs/ufshcd.h b/drivers/scsi/ufs/ufshcd.h index fa4b2e7883d9..4e219990dec6 100644 --- a/drivers/scsi/ufs/ufshcd.h +++ b/drivers/scsi/ufs/ufshcd.h @@ -609,6 +609,7 @@ enum ufshcd_ctx { H8_EXIT_WORK, UIC_CMD_SEND, PWRCTL_CMD_SEND, + PWR_CHG_NOTIFY, TM_CMD_SEND, XFR_REQ_COMPL, CLK_SCALE_WORK, diff --git a/drivers/sensors/sensors_ssc.c b/drivers/sensors/sensors_ssc.c index dfdbd8e8df69..1f458052056e 100644 --- a/drivers/sensors/sensors_ssc.c +++ b/drivers/sensors/sensors_ssc.c @@ -112,12 +112,21 @@ static void slpi_load_fw(struct work_struct *slpi_ldr_work) } priv->pil_h = subsystem_get_with_fwname("slpi", firmware_name); + if (IS_ERR(priv->pil_h)) { + dev_err(&pdev->dev, "%s: pil get failed,\n", + __func__); + } else { + goto exit; + } + + priv->pil_h = subsystem_get_with_fwname("slpi", "slpi"); if (IS_ERR(priv->pil_h)) { dev_err(&pdev->dev, "%s: pil get failed,\n", __func__); goto fail; } +exit: dev_dbg(&pdev->dev, "%s: SLPI image is loaded\n", __func__); return; diff --git a/drivers/soc/qcom/hyp_core_ctl.c b/drivers/soc/qcom/hyp_core_ctl.c index e99279f490d4..02a9d10bfd5a 100644 --- a/drivers/soc/qcom/hyp_core_ctl.c +++ b/drivers/soc/qcom/hyp_core_ctl.c @@ -26,6 +26,7 @@ #include #include #include +#include #include diff --git a/drivers/soc/qcom/icnss.c b/drivers/soc/qcom/icnss.c index 0ae9758d5008..f4e649da7b45 100644 --- a/drivers/soc/qcom/icnss.c +++ b/drivers/soc/qcom/icnss.c @@ -3826,6 +3826,8 @@ static int icnss_probe(struct platform_device *pdev) goto out_unregister_ext_modem; } + device_enable_async_suspend(dev); + spin_lock_init(&priv->event_lock); spin_lock_init(&priv->on_off_lock); mutex_init(&priv->dev_lock); @@ -4055,6 +4057,7 @@ static struct platform_driver icnss_driver = { .pm = &icnss_pm_ops, .owner = THIS_MODULE, .of_match_table = icnss_dt_match, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/soc/qcom/msm_bus/msm_bus_rules.c b/drivers/soc/qcom/msm_bus/msm_bus_rules.c index df9b9770f07a..aa101b8ab2cf 100644 --- a/drivers/soc/qcom/msm_bus/msm_bus_rules.c +++ b/drivers/soc/qcom/msm_bus/msm_bus_rules.c @@ -16,7 +16,6 @@ #include #include #include -#include struct node_vote_info { int id; @@ -214,11 +213,6 @@ static void match_rule(struct rule_update_path_info *inp_node, continue; if (check_rule(rule, inp_node)) { - trace_bus_rules_matches( - (node->cur_rule ? - node->cur_rule->rule_id : -1), - inp_node->id, inp_node->ab, - inp_node->ib, inp_node->clk); if (rule->state == RULE_STATE_NOT_APPLIED) rule->state_change = true; diff --git a/drivers/soc/qcom/smp2p.c b/drivers/soc/qcom/smp2p.c index bfc4aad91f44..0a39cf577081 100644 --- a/drivers/soc/qcom/smp2p.c +++ b/drivers/soc/qcom/smp2p.c @@ -702,7 +702,7 @@ static int qcom_smp2p_probe(struct platform_device *pdev) ret = devm_request_threaded_irq(&pdev->dev, smp2p->irq, qcom_smp2p_isr, qcom_smp2p_intr, - IRQF_NO_SUSPEND | IRQF_ONESHOT, + IRQF_ONESHOT, "smp2p", (void *)smp2p); if (ret) { dev_err(&pdev->dev, "failed to request interrupt\n"); diff --git a/drivers/soc/qcom/smp2p_sleepstate.c b/drivers/soc/qcom/smp2p_sleepstate.c index 443f4c23b4fa..e43cf27299cd 100644 --- a/drivers/soc/qcom/smp2p_sleepstate.c +++ b/drivers/soc/qcom/smp2p_sleepstate.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -18,6 +18,7 @@ #include #include #include +#include #define PROC_AWAKE_ID 12 /* 12th bit */ #define AWAKE_BIT BIT(PROC_AWAKE_ID) @@ -39,6 +40,7 @@ static int sleepstate_pm_notifier(struct notifier_block *nb, switch (event) { case PM_SUSPEND_PREPARE: qcom_smem_state_update_bits(state, AWAKE_BIT, 0); + usleep_range(10000, 10500); /* Tuned based on SMP2P latencies */ break; case PM_POST_SUSPEND: diff --git a/drivers/soc/qcom/socinfo.c b/drivers/soc/qcom/socinfo.c index d480088fc342..127310eb741e 100644 --- a/drivers/soc/qcom/socinfo.c +++ b/drivers/soc/qcom/socinfo.c @@ -70,6 +70,7 @@ enum { HW_PLATFORM_HDK = 31, HW_PLATFORM_IOT = 32, HW_PLATFORM_IDP = 34, + HW_PLATFORM_F1 = 37, HW_PLATFORM_INVALID }; @@ -93,7 +94,8 @@ const char *hw_platform[] = { [HW_PLATFORM_ADP] = "ADP", [HW_PLATFORM_HDK] = "HDK", [HW_PLATFORM_IOT] = "IOT", - [HW_PLATFORM_IDP] = "IDP" + [HW_PLATFORM_IDP] = "IDP", + [HW_PLATFORM_F1] = "CEPHEUS", }; enum { @@ -1761,6 +1763,16 @@ static void socinfo_select_format(void) } } +uint32_t get_hw_version_platform(void) +{ + uint32_t hw_type = socinfo_get_platform_type(); + if (hw_type == HW_PLATFORM_F1) + return HARDWARE_PLATFORM_CEPHEUS; + else + return HARDWARE_PLATFORM_UNKNOWN; +} +EXPORT_SYMBOL(get_hw_version_platform); + int __init socinfo_init(void) { static bool socinfo_init_done; diff --git a/drivers/spi/spi-geni-qcom.c b/drivers/spi/spi-geni-qcom.c index 5577567eab5b..2e056472b1e0 100644 --- a/drivers/spi/spi-geni-qcom.c +++ b/drivers/spi/spi-geni-qcom.c @@ -28,7 +28,7 @@ #include #define SPI_NUM_CHIPSELECT (4) -#define SPI_XFER_TIMEOUT_MS (250) +#define SPI_XFER_TIMEOUT_MS (1500) #define SPI_AUTO_SUSPEND_DELAY (250) /* SPI SE specific registers */ #define SE_SPI_CPHA (0x224) diff --git a/drivers/staging/android/ion/msm/msm_ion_of.c b/drivers/staging/android/ion/msm/msm_ion_of.c index 4580bd47f57c..062958df6f30 100644 --- a/drivers/staging/android/ion/msm/msm_ion_of.c +++ b/drivers/staging/android/ion/msm/msm_ion_of.c @@ -375,6 +375,7 @@ static struct platform_driver msm_ion_driver = { .driver = { .name = "ion-msm", .of_match_table = msm_ion_match_table, + .probe_type = PROBE_PREFER_ASYNCHRONOUS, }, }; diff --git a/drivers/staging/greybus/tools/Android.mk b/drivers/staging/greybus/tools/Android.mk deleted file mode 100644 index fdadbf611757..000000000000 --- a/drivers/staging/greybus/tools/Android.mk +++ /dev/null @@ -1,10 +0,0 @@ -LOCAL_PATH:= $(call my-dir) - -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= loopback_test.c -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE := gb_loopback_test - -include $(BUILD_EXECUTABLE) - diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_trace.h b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_trace.h index 03c69da15b39..201a38825cdc 100644 --- a/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_trace.h +++ b/drivers/staging/qca-wifi-host-cmn/qdf/inc/qdf_trace.h @@ -1136,11 +1136,11 @@ struct category_name_info { * Return: nothing * */ -void qdf_trace_msg_cmn(unsigned int idx, +static inline void qdf_trace_msg_cmn(unsigned int idx, QDF_MODULE_ID category, QDF_TRACE_LEVEL verbose, const char *str_format, - va_list val); + va_list val) {} /** * struct qdf_print_ctrl: QDF Print Control structure @@ -1252,8 +1252,10 @@ QDF_STATUS qdf_print_set_category_verbose(unsigned int idx, * * Return : Verbose enabled(true) or disabled(false) or invalid input (false) */ -bool qdf_print_is_category_enabled(unsigned int idx, - QDF_MODULE_ID category); +static inline bool qdf_print_is_category_enabled(unsigned int idx, + QDF_MODULE_ID category) { + return false; +} /** * qdf_print_is_verbose_enabled() - Get verbose information of a category for @@ -1265,9 +1267,11 @@ bool qdf_print_is_category_enabled(unsigned int idx, * * Return : Verbose enabled(true) or disabled(false) or invalid input (false) */ -bool qdf_print_is_verbose_enabled(unsigned int idx, +static inline bool qdf_print_is_verbose_enabled(unsigned int idx, QDF_MODULE_ID category, - QDF_TRACE_LEVEL verbose); + QDF_TRACE_LEVEL verbose) { + return false; +} /** * qdf_print_clean_node_flag() - Clean up node flag for print control object diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_trace.h b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_trace.h index fbc436e21651..f59c9760ce5c 100644 --- a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_trace.h +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/i_qdf_trace.h @@ -71,10 +71,10 @@ } \ } while (0) #else -#define QDF_TRACE(arg ...) -#define QDF_VTRACE(arg ...) -#define QDF_TRACE_HEX_DUMP(arg ...) -#define __QDF_TRACE_RATE_LIMITED(arg ...) +#define QDF_TRACE(x...) ((void)0) +#define QDF_VTRACE(x...) ((void)0) +#define QDF_TRACE_HEX_DUMP(x...) ((void)0) +#define __QDF_TRACE_RATE_LIMITED(x...) ((void)0) #endif #else /* CONFIG_MCL */ diff --git a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c index e14b56df6c32..526a60043e3c 100644 --- a/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c +++ b/drivers/staging/qca-wifi-host-cmn/qdf/linux/src/qdf_trace.c @@ -1876,7 +1876,7 @@ void qdf_dp_display_proto_pkt_always(struct qdf_dp_trace_record_s *record, { int loc; char prepend_str[QDF_DP_TRACE_PREPEND_STR_SIZE]; - struct qdf_dp_trace_proto_buf *buf = + struct qdf_dp_trace_proto_buf *buf __maybe_unused = (struct qdf_dp_trace_proto_buf *)record->data; qdf_mem_zero(prepend_str, sizeof(prepend_str)); @@ -2848,6 +2848,7 @@ static inline void print_to_console(char *str_buffer) } #endif +#if 0 #ifdef MULTI_IF_NAME static const char *qdf_trace_wlan_modname(void) { @@ -2931,6 +2932,7 @@ void qdf_trace_msg_cmn(unsigned int idx, } } qdf_export_symbol(qdf_trace_msg_cmn); +#endif QDF_STATUS qdf_print_setup(void) { @@ -3353,6 +3355,7 @@ QDF_STATUS qdf_print_set_category_verbose(unsigned int idx, } qdf_export_symbol(qdf_print_set_category_verbose); +#if 0 bool qdf_print_is_category_enabled(unsigned int idx, QDF_MODULE_ID category) { QDF_TRACE_LEVEL verbose_mask; @@ -3424,6 +3427,7 @@ bool qdf_print_is_verbose_enabled(unsigned int idx, QDF_MODULE_ID category, return verbose_enabled; } qdf_export_symbol(qdf_print_is_verbose_enabled); +#endif #ifdef DBG_LVL_MAC_FILTERING diff --git a/drivers/staging/qca-wifi-host-cmn/utils/fwlog/dbglog_host.h b/drivers/staging/qca-wifi-host-cmn/utils/fwlog/dbglog_host.h index 9606689a5741..dfea2d894a68 100644 --- a/drivers/staging/qca-wifi-host-cmn/utils/fwlog/dbglog_host.h +++ b/drivers/staging/qca-wifi-host-cmn/utils/fwlog/dbglog_host.h @@ -72,7 +72,8 @@ extern "C" { #ifdef FEATURE_FW_LOG_PARSING /* * set the dbglog parser type - */int + */ +int dbglog_parser_type_init(wmi_unified_t wmi_handle, int type); /** dbglog_int - Registers a WMI event handle for WMI_DBGMSG_EVENT diff --git a/drivers/staging/qca-wifi-host-cmn/utils/host_diag_log/src/i_host_diag_core_event.h b/drivers/staging/qca-wifi-host-cmn/utils/host_diag_log/src/i_host_diag_core_event.h index 50240f48132c..947256a8f428 100644 --- a/drivers/staging/qca-wifi-host-cmn/utils/host_diag_log/src/i_host_diag_core_event.h +++ b/drivers/staging/qca-wifi-host-cmn/utils/host_diag_log/src/i_host_diag_core_event.h @@ -212,15 +212,14 @@ static inline void qdf_wow_wakeup_host_event(uint8_t wow_wakeup_cause) return; } -static inline void host_log_acs_req_event(uint8_t *intf, uint8_t *hw_mode, +static inline void host_log_acs_req_event(uint8_t *intf, const uint8_t *hw_mode, uint16_t bw, uint8_t ht, uint8_t vht, uint16_t chan_start, uint16_t chan_end) { } -static inline void host_log_acs_scan_start(uint8_t *scan_type, - uint8_t *bss_type, uint32_t scan_id, +static inline void host_log_acs_scan_start(uint32_t scan_id, uint8_t vdev_id) { } diff --git a/drivers/staging/qca-wifi-host-cmn/utils/logging/inc/wlan_roam_debug.h b/drivers/staging/qca-wifi-host-cmn/utils/logging/inc/wlan_roam_debug.h index 844da5d82a56..df872e13dc99 100644 --- a/drivers/staging/qca-wifi-host-cmn/utils/logging/inc/wlan_roam_debug.h +++ b/drivers/staging/qca-wifi-host-cmn/utils/logging/inc/wlan_roam_debug.h @@ -99,6 +99,7 @@ enum peer_debug_op { #define DEBUG_INVALID_PEER_ID 0xffff #define DEBUG_INVALID_VDEV_ID 0xff +#ifdef WLAN_DEBUG /** * wlan_roam_debug_log() - Add a debug log entry to wlan roam debug records * @vdev_id: vdev identifier @@ -122,4 +123,11 @@ void wlan_roam_debug_log(uint8_t vdev_id, uint8_t op, * Return: none */ void wlan_roam_debug_dump_table(void); +#else +static inline void wlan_roam_debug_log(uint8_t vdev_id, uint8_t op, + uint16_t peer_id, void *mac_addr, + void *peer_obj, uint32_t arg1, uint32_t arg2) {} +static inline void wlan_roam_debug_dump_table(void) {} +#endif + #endif /* _WLAN_ROAM_DEBUG_H_ */ diff --git a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_priv.h b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_priv.h index 7ea6440084e5..c68c6fa9e64d 100644 --- a/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_priv.h +++ b/drivers/staging/qca-wifi-host-cmn/wmi/inc/wmi_unified_priv.h @@ -54,8 +54,6 @@ #define WMI_UNIFIED_MAX_EVENT 0x100 -#ifdef WMI_INTERFACE_EVENT_LOGGING - #ifndef WMI_EVENT_DEBUG_MAX_ENTRY #define WMI_EVENT_DEBUG_MAX_ENTRY (1024) #endif @@ -92,6 +90,8 @@ #define wmi_info_rl(params...) QDF_TRACE_INFO_RL(QDF_MODULE_ID_WMI, params) #define wmi_debug_rl(params...) QDF_TRACE_DEBUG_RL(QDF_MODULE_ID_WMI, params) +#ifdef WMI_INTERFACE_EVENT_LOGGING + /** * struct wmi_command_debug - WMI command log buffer data type * @ command - Store WMI Command id diff --git a/drivers/staging/qcacld-3.0/Kbuild b/drivers/staging/qcacld-3.0/Kbuild index 7c5d507578fa..546f8b2e460f 100644 --- a/drivers/staging/qcacld-3.0/Kbuild +++ b/drivers/staging/qcacld-3.0/Kbuild @@ -1464,9 +1464,7 @@ ifeq ($(CONFIG_REMOVE_PKT_LOG), n) INCS += $(PKTLOG_INC) endif -ifeq ($(BUILD_DIAG_VERSION), y) INCS += $(HOST_DIAG_LOG_INC) -endif INCS += $(DISA_INC) INCS += $(ACTION_OUI_INC) @@ -1531,7 +1529,9 @@ OBJS += $(UMAC_TDLS_OBJS) OBJS += $(PMO_OBJS) OBJS += $(UMAC_P2P_OBJS) OBJS += $(UMAC_POLICY_MGR_OBJS) -OBJS += $(WLAN_LOGGING_OBJS) +ifeq ($(BUILD_DEBUG_VERSION), 1) +OBJS += $(WLAN_LOGGING_OBJS) $(FWLOG_OBJS) +endif OBJS += $(NLINK_OBJS) OBJS += $(PTT_OBJS) OBJS += $(UMAC_SER_OBJS) diff --git a/drivers/staging/qcacld-3.0/configs/default_defconfig b/drivers/staging/qcacld-3.0/configs/default_defconfig index ba1ccdf067f4..8f0205d44a6b 100644 --- a/drivers/staging/qcacld-3.0/configs/default_defconfig +++ b/drivers/staging/qcacld-3.0/configs/default_defconfig @@ -34,7 +34,6 @@ ifeq ($(CONFIG_ICNSS), y) CONFIG_HELIUMPLUS := y CONFIG_64BIT_PADDR := y CONFIG_FEATURE_TSO := y - CONFIG_FEATURE_TSO_DEBUG := y ifeq ($(CONFIG_INET_LRO), y) CONFIG_WLAN_LRO := y else @@ -200,9 +199,8 @@ ifeq ($(CONFIG_ROME_IF),usb) CONFIG_LINUX_QCMBR :=y endif -CONFIG_MPC_UT_FRAMEWORK := y - -CONFIG_FEATURE_EPPING := y +CONFIG_MPC_UT_FRAMEWORK := n +CONFIG_FEATURE_EPPING := n #Flag to enable offload packets feature CONFIG_WLAN_OFFLOAD_PACKETS := y @@ -315,37 +313,12 @@ CONFIG_DP_INTR_POLL_BASED := y CONFIG_TX_PER_PDEV_DESC_POOL := y CONFIG_DP_TRACE := y CONFIG_FEATURE_TSO := y -CONFIG_TSO_DEBUG_LOG_ENABLE := y CONFIG_DP_LFR := y CONFIG_HTT_PADDR64 := y CONFIG_RX_OL := y CONFIG_TX_TID_OVERRIDE := y endif -# As per target team, build is done as follows: -# Defconfig : build with default flags -# Slub : defconfig + CONFIG_SLUB_DEBUG=y + -# CONFIG_SLUB_DEBUG_ON=y + CONFIG_PAGE_POISONING=y -# Perf : Using appropriate msmXXXX-perf_defconfig -# -# Shipment builds (user variants) should not have any debug feature -# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds -# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since -# there is no other way to identify defconfig builds, QCOMs internal -# representation of perf builds (identified using the string 'perf'), -# is used to identify if the build is a slub or defconfig one. This -# way no critical debug feature will be enabled for perf and shipment -# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT -# config. -ifneq ($(TARGET_BUILD_VARIANT),user) - ifeq ($(CONFIG_LITHIUM), y) - CONFIG_FEATURE_PKTLOG := n - else - CONFIG_FEATURE_PKTLOG := y - endif - CONFIG_WLAN_DEBUG_CRASH_INJECT := y -endif - #Enable WLAN/Power debugfs feature only if debug_fs is enabled ifeq ($(CONFIG_DEBUG_FS), y) # Flag to enable debugfs. Depends on CONFIG_DEBUG_FS in kernel @@ -360,10 +333,17 @@ endif # Feature flags which are not (currently) configurable via Kconfig #Whether to build debug version -BUILD_DEBUG_VERSION := y +BUILD_DEBUG_VERSION := n #Enable this flag to build driver in diag version -BUILD_DIAG_VERSION := y +BUILD_DIAG_VERSION := n + +# Debug specific features +CONFIG_FEATURE_TSO_DEBUG := n +CONFIG_WLAN_NAPI_DEBUG := n +CONFIG_WLAN_FEATURE_P2P_DEBUG := n +CONFIG_FEATURE_FW_LOG_PARSING := n +CONFIG_DP_TRACE := n ifeq ($(CONFIG_SLUB_DEBUG), y) PANIC_ON_BUG := y @@ -381,7 +361,6 @@ CONFIG_WLAN_LOG_FATAL := y CONFIG_WLAN_LOG_ERROR := y CONFIG_WLAN_LOG_WARN := y CONFIG_WLAN_LOG_INFO := y -CONFIG_WLAN_LOG_DEBUG := y #Enable OL debug and wmi unified functions CONFIG_ATH_PERF_PWR_OFFLOAD := y @@ -555,7 +534,7 @@ CONFIG_QCA_SIGNED_SPLIT_BINARY_SUPPORT := n CONFIG_QCA_SINGLE_BINARY_SUPPORT := n #Enable collecting target RAM dump after kernel panic -CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := y +CONFIG_TARGET_RAMDUMP_AFTER_KERNEL_PANIC := n #Flag to enable/disable secure firmware feature CONFIG_FEATURE_SECURE_FIRMWARE := n @@ -567,19 +546,13 @@ CONFIG_FEATURE_STATS_EXT := y CONFIG_FEATURE_HTC_CREDIT_HISTORY := y #Flag to enable MTRACE feature -CONFIG_TRACE_RECORD_FEATURE := y - -#Flag to enable p2p debug feature -CONFIG_WLAN_FEATURE_P2P_DEBUG := y +CONFIG_TRACE_RECORD_FEATURE := n #Flag to enable DFS Master feature CONFIG_WLAN_DFS_MASTER_ENABLE := y -#Flag to enable/disable MTRACE feature -CONFIG_ENABLE_MTRACE_LOG := y - #Flag to enable nud tracking feature -CONFIG_WLAN_NUD_TRACKING := y +CONFIG_WLAN_NUD_TRACKING := n #Flag to enable wbuff feature CONFIG_WLAN_WBUFF := y @@ -595,15 +568,12 @@ ifneq ($(CONFIG_WIFI_POS_CONVERGED), y) CONFIG_WIFI_POS_LEGACY := y endif -CONFIG_CP_STATS := y +CONFIG_CP_STATS := n CONFIG_FEATURE_WLAN_WAPI := y CONFIG_AGEIE_ON_SCAN_RESULTS := y -#Flag to enable FW log parsing support feature -CONFIG_FEATURE_FW_LOG_PARSING := y - CONFIG_PTT_SOCK_SVC_ENABLE := y CONFIG_SOFTAP_CHANNEL_RANGE := y CONFIG_FEATURE_WLAN_SCAN_PNO := y @@ -612,7 +582,7 @@ CONFIG_WLAN_NS_OFFLOAD := y CONFIG_FEATURE_WLAN_RA_FILTERING:= y CONFIG_FEATURE_WLAN_LPHB := y CONFIG_QCA_SUPPORT_TX_THROTTLE := y -CONFIG_WMI_INTERFACE_EVENT_LOGGING := y +CONFIG_WMI_INTERFACE_EVENT_LOGGING := n CONFIG_WLAN_FEATURE_LINK_LAYER_STATS := y CONFIG_FEATURE_WLAN_EXTSCAN := y CONFIG_160MHZ_SUPPORT := y @@ -628,7 +598,9 @@ CONFIG_CONVERGED_TDLS_ENABLE := y CONFIG_WLAN_CONV_SPECTRAL_ENABLE := y CONFIG_WLAN_SPECTRAL_ENABLE := y CONFIG_WMI_CMD_STRINGS := y -CONFIG_FEATURE_MONITOR_MODE_SUPPORT := y +CONFIG_FEATURE_MONITOR_MODE_SUPPORT := n +CONFIG_DESC_DUP_DETECT_DEBUG := n +CONFIG_DEBUG_RX_RING_BUFFER := n CONFIG_WLAN_FEATURE_TWT := y ifeq ($(CONFIG_HELIUMPLUS), y) @@ -651,9 +623,6 @@ ifeq ($(CONFIG_LITHIUM), y) CONFIG_FEATURE_UNIT_TEST_SUSPEND := y endif -#Flag to enable hdd memory dump feature -CONFIG_FEATURE_MEMDUMP_ENABLE := y - #Flag to enable/disable WLAN D0-WOW ifeq ($(CONFIG_PCI_MSM), y) ifeq ($(CONFIG_HIF_PCI), y) @@ -674,18 +643,8 @@ ifeq ($(CONFIG_ARCH_MSM8996), y) CONFIG_CHANNEL_HOPPING_ALL_BANDS := y endif -ifneq ($(CONFIG_HIF_USB), y) -CONFIG_WLAN_LOGGING_SOCK_SVC := y -endif - -ifneq ($(TARGET_BUILD_VARIANT),user) -CONFIG_DESC_DUP_DETECT_DEBUG := y -CONFIG_DEBUG_RX_RING_BUFFER := y -endif - -CONFIG_DP_TRACE := y -#Enable Beacon Reception Stats -CONFIG_FEATURE_BECN_STATS := y +CONFIG_WLAN_LOGGING_SOCK_SVC := n +CONFIG_FEATURE_BECN_STATS := n #enable MPTA helper for QCS405 ifeq ($(CONFIG_ARCH_QCS405), y) diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h index 38ec5c0291e4..b428c354844e 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_cfg.h @@ -11175,30 +11175,6 @@ enum dot11p_mode { #define CFG_CRASH_FW_TIMEOUT_ENABLE (1) #define CFG_CRASH_FW_TIMEOUT_DEFAULT (1) -/* - * - * rx_wakelock_timeout - Amount of time to hold wakelock for RX unicast packets - * @Min: 0 - * @Max: 100 - * @Default: 50 - * - * This ini item configures the amount of time, in milliseconds, that the driver - * should prevent system power collapse after receiving an RX unicast packet. - * A conigured value of 0 disables the RX Wakelock feature completely. - * - * Related: None. - * - * Supported Feature: RX Wakelock - * - * Usage: Internal/External - * - * - */ -#define CFG_RX_WAKELOCK_TIMEOUT_NAME "rx_wakelock_timeout" -#define CFG_RX_WAKELOCK_TIMEOUT_DEFAULT (50) -#define CFG_RX_WAKELOCK_TIMEOUT_MIN (0) -#define CFG_RX_WAKELOCK_TIMEOUT_MAX (100) - /* * * enable_5g_band_pref - Enable preference for 5G from INI. @@ -13551,7 +13527,7 @@ enum hdd_external_acs_policy { */ #define CFG_IS_SAE_ENABLED_NAME "sae_enabled" -#define CFG_IS_SAE_ENABLED_DEFAULT (1) +#define CFG_IS_SAE_ENABLED_DEFAULT (0) #define CFG_IS_SAE_ENABLED_MIN (0) #define CFG_IS_SAE_ENABLED_MAX (1) @@ -14952,7 +14928,7 @@ enum hdd_external_acs_policy { #define CFG_ENABLE_GCMP_NAME "gcmp_enabled" #define CFG_ENABLE_GCMP_MIN (0) #define CFG_ENABLE_GCMP_MAX (1) -#define CFG_ENABLE_GCMP_DEFAULT (1) +#define CFG_ENABLE_GCMP_DEFAULT (0) /* * @@ -17713,7 +17689,6 @@ struct hdd_config { /* beacon count before channel switch */ uint8_t sap_chanswitch_beacon_cnt; uint8_t sap_chanswitch_mode; - uint32_t rx_wakelock_timeout; uint32_t max_sched_scan_plan_interval; uint32_t max_sched_scan_plan_iterations; #ifdef WLAN_FEATURE_WOW_PULSE diff --git a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h index 85b0adc60189..14ad5a6febab 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h +++ b/drivers/staging/qcacld-3.0/core/hdd/inc/wlan_hdd_main.h @@ -1839,7 +1839,6 @@ struct hdd_context { /** P2P Device MAC Address for the adapter */ struct qdf_mac_addr p2p_device_address; - qdf_wake_lock_t rx_wake_lock; qdf_wake_lock_t sap_wake_lock; void *hdd_ipa; diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c index ab8c9270da72..9ba80cbb29dc 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_assoc.c @@ -2184,8 +2184,10 @@ QDF_STATUS hdd_roam_register_sta(struct hdd_adapter *adapter, hdd_conn_set_authenticated(adapter, true); hdd_objmgr_set_peer_mlme_auth_state(adapter->vdev, true); } else { +#ifdef WLAN_DEBUG hdd_debug("ULA auth StaId= %d. Changing TL state to CONNECTED at Join time", sta_ctx->conn_info.staId[0]); +#endif qdf_status = hdd_change_peer_state(adapter, staDesc.sta_id, OL_TXRX_PEER_STATE_CONN, diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c index dfef519dd887..a13c4426fe65 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg.c @@ -4586,12 +4586,6 @@ struct reg_table_entry g_registry_table[] = { CFG_CRASH_FW_TIMEOUT_DEFAULT, CFG_CRASH_FW_TIMEOUT_DISABLE, CFG_CRASH_FW_TIMEOUT_ENABLE), - REG_VARIABLE(CFG_RX_WAKELOCK_TIMEOUT_NAME, WLAN_PARAM_Integer, - struct hdd_config, rx_wakelock_timeout, - VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, - CFG_RX_WAKELOCK_TIMEOUT_DEFAULT, - CFG_RX_WAKELOCK_TIMEOUT_MIN, - CFG_RX_WAKELOCK_TIMEOUT_MAX), REG_VARIABLE(CFG_SAP_CH_SWITCH_BEACON_CNT, WLAN_PARAM_Integer, struct hdd_config, sap_chanswitch_beacon_cnt, VAR_FLAGS_OPTIONAL | VAR_FLAGS_RANGE_CHECK_ASSUME_DEFAULT, @@ -7163,7 +7157,6 @@ static void hdd_cfg_print_action_oui(struct hdd_context *hdd_ctx) { #ifdef WLAN_DEBUG struct hdd_config *config = hdd_ctx->config; -#endif hdd_debug("Name = [%s] value = [%u]", CFG_ENABLE_ACTION_OUI, @@ -7200,6 +7193,7 @@ static void hdd_cfg_print_action_oui(struct hdd_context *hdd_ctx) hdd_debug("Name = [%s] value = [%s]", CFG_ACTION_OUI_DISABLE_AGGRESSIVE_EDCA, config->action_oui_str[ACTION_OUI_DISABLE_AGGRESSIVE_EDCA]); +#endif } /** diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c index 2a7f356e6d20..f86b14c5bfca 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_cfg80211.c @@ -5005,9 +5005,7 @@ static int __wlan_hdd_cfg80211_disable_dfs_chan_scan(struct wiphy *wiphy, const void *data, int data_len) { -#ifdef WLAN_DEBUG struct net_device *dev = wdev->netdev; -#endif struct hdd_context *hdd_ctx = wiphy_priv(wiphy); struct nlattr *tb[QCA_WLAN_VENDOR_ATTR_SET_NO_DFS_FLAG_MAX + 1]; int ret_val; @@ -21218,18 +21216,17 @@ static const char *hdd_ieee80211_reason_code_to_str(uint16_t reason) */ static void hdd_print_netdev_txq_status(struct net_device *dev) { +#ifdef WLAN_DEBUG unsigned int i; if (!dev) return; for (i = 0; i < dev->num_tx_queues; i++) { -#ifdef WLAN_DEBUG struct netdev_queue *txq = netdev_get_tx_queue(dev, i); -#endif - hdd_debug("netdev tx queue[%u] state: 0x%lx", i, txq->state); } +#endif } /** diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c index 43901107892f..c6f6f6223c64 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_main.c @@ -179,27 +179,7 @@ static unsigned int dev_num = 1; static struct cdev wlan_hdd_state_cdev; static struct class *class; static dev_t device; -#ifndef MODULE -static struct gwlan_loader *wlan_loader; -static ssize_t wlan_boot_cb(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, size_t count); -struct gwlan_loader { - bool loaded_state; - struct kobject *boot_wlan_obj; - struct attribute_group *attr_group; -}; - -static struct kobj_attribute wlan_boot_attribute = - __ATTR(boot_wlan, 0220, NULL, wlan_boot_cb); - -static struct attribute *attrs[] = { - &wlan_boot_attribute.attr, - NULL, -}; - -#define MODULE_INITIALIZED 1 -#endif +static bool hdd_loaded = false; #define HDD_OPS_INACTIVITY_TIMEOUT (120000) #define MAX_OPS_NAME_STRING_SIZE 20 @@ -7759,32 +7739,6 @@ static int hdd_init_netlink_services(struct hdd_context *hdd_ctx) return ret; } -/** - * hdd_rx_wake_lock_destroy() - Destroy RX wakelock - * @hdd_ctx: HDD context. - * - * Destroy RX wakelock. - * - * Return: None. - */ -static void hdd_rx_wake_lock_destroy(struct hdd_context *hdd_ctx) -{ - qdf_wake_lock_destroy(&hdd_ctx->rx_wake_lock); -} - -/** - * hdd_rx_wake_lock_create() - Create RX wakelock - * @hdd_ctx: HDD context. - * - * Create RX wakelock. - * - * Return: None. - */ -static void hdd_rx_wake_lock_create(struct hdd_context *hdd_ctx) -{ - qdf_wake_lock_create(&hdd_ctx->rx_wake_lock, "qcom_rx_wakelock"); -} - /** * hdd_context_deinit() - Deinitialize HDD context * @hdd_ctx: HDD context. @@ -7803,8 +7757,6 @@ static int hdd_context_deinit(struct hdd_context *hdd_ctx) hdd_sap_context_destroy(hdd_ctx); - hdd_rx_wake_lock_destroy(hdd_ctx); - hdd_scan_context_destroy(hdd_ctx); qdf_list_destroy(&hdd_ctx->hdd_adapters); @@ -8736,7 +8688,6 @@ void wlan_hdd_deinit_tx_rx_histogram(struct hdd_context *hdd_ctx) hdd_ctx->hdd_txrx_hist = NULL; } -#ifdef WLAN_DEBUG static uint8_t *convert_level_to_string(uint32_t level) { switch (level) { @@ -8753,8 +8704,6 @@ static uint8_t *convert_level_to_string(uint32_t level) return "INVAL"; } } -#endif - /** * wlan_hdd_display_tx_rx_histogram() - display tx rx histogram @@ -9805,8 +9754,6 @@ static int hdd_context_init(struct hdd_context *hdd_ctx) if (ret) goto list_destroy; - hdd_rx_wake_lock_create(hdd_ctx); - ret = hdd_sap_context_init(hdd_ctx); if (ret) goto scan_destroy; @@ -9830,7 +9777,6 @@ static int hdd_context_init(struct hdd_context *hdd_ctx) scan_destroy: hdd_scan_context_destroy(hdd_ctx); - hdd_rx_wake_lock_destroy(hdd_ctx); list_destroy: qdf_list_destroy(&hdd_ctx->hdd_adapters); @@ -13559,6 +13505,7 @@ static int wlan_hdd_state_ctrl_param_open(struct inode *inode, return 0; } +static int hdd_driver_load(void); static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, const char __user *user_buf, size_t count, @@ -13589,6 +13536,13 @@ static ssize_t wlan_hdd_state_ctrl_param_write(struct file *filp, goto exit; } + if (!hdd_loaded) { + if (hdd_driver_load()) { + pr_err("%s: Failed to init hdd module\n", __func__); + goto exit; + } + } + if (!cds_is_driver_loaded()) { init_completion(&wlan_start_comp); rc = wait_for_completion_timeout(&wlan_start_comp, @@ -13812,16 +13766,10 @@ static int hdd_driver_load(void) hdd_set_conparam(con_mode); - errno = wlan_hdd_state_ctrl_param_create(); - if (errno) { - hdd_fln("Failed to create ctrl param; errno:%d", errno); - goto wakelock_destroy; - } - errno = pld_init(); if (errno) { hdd_fln("Failed to init PLD; errno:%d", errno); - goto param_destroy; + goto wakelock_destroy; } errno = wlan_hdd_register_driver(); @@ -13830,14 +13778,13 @@ static int hdd_driver_load(void) goto pld_deinit; } + hdd_loaded = true; pr_info("%s: driver loaded\n", WLAN_MODULE_NAME); return 0; pld_deinit: pld_deinit(); -param_destroy: - wlan_hdd_state_ctrl_param_destroy(); wakelock_destroy: qdf_wake_lock_destroy(&wlan_wake_lock); comp_deinit: @@ -13882,133 +13829,6 @@ static void hdd_driver_unload(void) hdd_qdf_print_deinit(); } -#ifndef MODULE -/** - * wlan_boot_cb() - Wlan boot callback - * @kobj: object whose directory we're creating the link in. - * @attr: attribute the user is interacting with - * @buff: the buffer containing the user data - * @count: number of bytes in the buffer - * - * This callback is invoked when the fs is ready to start the - * wlan driver initialization. - * - * Return: 'count' on success or a negative error code in case of failure - */ -static ssize_t wlan_boot_cb(struct kobject *kobj, - struct kobj_attribute *attr, - const char *buf, - size_t count) -{ - - if (wlan_loader->loaded_state) { - hdd_fln("wlan driver already initialized"); - return -EALREADY; - } - - if (hdd_driver_load()) - return -EIO; - - wlan_loader->loaded_state = MODULE_INITIALIZED; - - return count; -} - -/** - * hdd_sysfs_cleanup() - cleanup sysfs - * - * Return: None - * - */ -static void hdd_sysfs_cleanup(void) -{ - /* remove from group */ - if (wlan_loader->boot_wlan_obj && wlan_loader->attr_group) - sysfs_remove_group(wlan_loader->boot_wlan_obj, - wlan_loader->attr_group); - - /* unlink the object from parent */ - kobject_del(wlan_loader->boot_wlan_obj); - - /* free the object */ - kobject_put(wlan_loader->boot_wlan_obj); - - kfree(wlan_loader->attr_group); - kfree(wlan_loader); - - wlan_loader = NULL; -} - -/** - * wlan_init_sysfs() - Creates the sysfs to be invoked when the fs is - * ready - * - * This is creates the syfs entry boot_wlan. Which shall be invoked - * when the filesystem is ready. - * - * QDF API cannot be used here since this function is called even before - * initializing WLAN driver. - * - * Return: 0 for success, errno on failure - */ -static int wlan_init_sysfs(void) -{ - int ret = -ENOMEM; - - wlan_loader = kzalloc(sizeof(*wlan_loader), GFP_KERNEL); - if (!wlan_loader) - return -ENOMEM; - - wlan_loader->boot_wlan_obj = NULL; - wlan_loader->attr_group = kzalloc(sizeof(*(wlan_loader->attr_group)), - GFP_KERNEL); - if (!wlan_loader->attr_group) - goto error_return; - - wlan_loader->loaded_state = 0; - wlan_loader->attr_group->attrs = attrs; - - wlan_loader->boot_wlan_obj = kobject_create_and_add("boot_wlan", - kernel_kobj); - if (!wlan_loader->boot_wlan_obj) { - hdd_fln("sysfs create and add failed"); - goto error_return; - } - - ret = sysfs_create_group(wlan_loader->boot_wlan_obj, - wlan_loader->attr_group); - if (ret) { - hdd_fln("sysfs create group failed; errno:%d", ret); - goto error_return; - } - - return 0; - -error_return: - hdd_sysfs_cleanup(); - - return ret; -} - -/** - * wlan_deinit_sysfs() - Removes the sysfs created to initialize the wlan - * - * Return: 0 on success or errno on failure - */ -static int wlan_deinit_sysfs(void) -{ - if (!wlan_loader) { - hdd_fln("wlan loader context is Null!"); - return -EINVAL; - } - - hdd_sysfs_cleanup(); - return 0; -} - -#endif /* MODULE */ - -#ifdef MODULE /** * hdd_module_init() - Module init helper * @@ -14018,26 +13838,15 @@ static int wlan_deinit_sysfs(void) */ static int hdd_module_init(void) { - if (hdd_driver_load()) - return -EINVAL; - - return 0; -} -#else -static int __init hdd_module_init(void) -{ - int ret = -EINVAL; + int ret; - ret = wlan_init_sysfs(); + ret = wlan_hdd_state_ctrl_param_create(); if (ret) - hdd_fln("Failed to create sysfs entry"); + pr_err("wlan_hdd_state_create:%x\n", ret); return ret; } -#endif - -#ifdef MODULE /** * hdd_module_exit() - Exit function * @@ -14049,13 +13858,6 @@ static void __exit hdd_module_exit(void) { hdd_driver_unload(); } -#else -static void __exit hdd_module_exit(void) -{ - hdd_driver_unload(); - wlan_deinit_sysfs(); -} -#endif #undef hdd_fln diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c index aee557c78cf4..6427c2bbfedf 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -949,19 +949,6 @@ QDF_STATUS hdd_softap_rx_packet_cbk(void *context, qdf_nbuf_t rx_buf) skb->protocol = eth_type_trans(skb, skb->dev); - /* hold configurable wakelock for unicast traffic */ - if (!hdd_is_current_high_throughput(hdd_ctx) && - hdd_ctx->config->rx_wakelock_timeout && - skb->pkt_type != PACKET_BROADCAST && - skb->pkt_type != PACKET_MULTICAST) { - cds_host_diag_log_work(&hdd_ctx->rx_wake_lock, - hdd_ctx->config->rx_wakelock_timeout, - WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); - qdf_wake_lock_timeout_acquire(&hdd_ctx->rx_wake_lock, - hdd_ctx->config-> - rx_wakelock_timeout); - } - /* Remove SKB from internal tracking table before submitting * it to stack */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c index 6ebbb96c2f15..4b6314d833f1 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_tx_rx.c @@ -352,6 +352,7 @@ uint32_t hdd_txrx_get_tx_ack_count(struct hdd_adapter *adapter) adapter->session_id); } +#ifdef FEATURE_WLAN_DIAG_SUPPORT /** * qdf_event_eapol_log() - send event to wlan diag * @skb: skb ptr @@ -393,7 +394,7 @@ void hdd_event_eapol_log(struct sk_buff *skb, enum qdf_proto_dir dir) WLAN_HOST_DIAG_EVENT_REPORT(&wlan_diag_event, EVENT_WLAN_EAPOL); } - +#endif /** * wlan_hdd_classify_pkt() - classify packet @@ -1403,66 +1404,6 @@ static bool hdd_is_mcast_replay(struct sk_buff *skb) return false; } -/** - * hdd_is_arp_local() - check if local or non local arp - * @skb: pointer to sk_buff - * - * Return: true if local arp or false otherwise. - */ -static bool hdd_is_arp_local(struct sk_buff *skb) -{ - struct arphdr *arp; - struct in_ifaddr **ifap = NULL; - struct in_ifaddr *ifa = NULL; - struct in_device *in_dev; - unsigned char *arp_ptr; - __be32 tip; - - arp = (struct arphdr *)skb->data; - if (arp->ar_op == htons(ARPOP_REQUEST)) { - in_dev = __in_dev_get_rtnl(skb->dev); - if (in_dev) { - for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) { - if (!strcmp(skb->dev->name, ifa->ifa_label)) - break; - } - } - - if (ifa && ifa->ifa_local) { - arp_ptr = (unsigned char *)(arp + 1); - arp_ptr += (skb->dev->addr_len + 4 + - skb->dev->addr_len); - memcpy(&tip, arp_ptr, 4); - hdd_debug("ARP packet: local IP: %x dest IP: %x", - ifa->ifa_local, tip); - if (ifa->ifa_local == tip) - return true; - } - } - - return false; -} - -/** - * hdd_is_rx_wake_lock_needed() - check if wake lock is needed - * @skb: pointer to sk_buff - * - * RX wake lock is needed for: - * 1) Unicast data packet OR - * 2) Local ARP data packet - * - * Return: true if wake lock is needed or false otherwise. - */ -static bool hdd_is_rx_wake_lock_needed(struct sk_buff *skb) -{ - if ((skb->pkt_type != PACKET_BROADCAST && - skb->pkt_type != PACKET_MULTICAST) || hdd_is_arp_local(skb)) - return true; - - return false; -} - #ifdef RECEIVE_OFFLOAD /** * hdd_resolve_rx_ol_mode() - Resolve Rx offload method, LRO or GRO @@ -1799,7 +1740,6 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) struct hdd_station_ctx *sta_ctx = NULL; unsigned int cpu_index; struct qdf_mac_addr *mac_addr, *dest_mac_addr; - bool wake_lock = false; uint8_t pkt_type = 0; bool track_arp = false; struct wlan_objmgr_vdev *vdev; @@ -1915,21 +1855,6 @@ QDF_STATUS hdd_rx_packet_cbk(void *context, qdf_nbuf_t rxBuf) continue; } - /* hold configurable wakelock for unicast traffic */ - if (!hdd_is_current_high_throughput(hdd_ctx) && - hdd_ctx->config->rx_wakelock_timeout && - sta_ctx->conn_info.uIsAuthenticated) - wake_lock = hdd_is_rx_wake_lock_needed(skb); - - if (wake_lock) { - cds_host_diag_log_work(&hdd_ctx->rx_wake_lock, - hdd_ctx->config->rx_wakelock_timeout, - WIFI_POWER_EVENT_WAKELOCK_HOLD_RX); - qdf_wake_lock_timeout_acquire(&hdd_ctx->rx_wake_lock, - hdd_ctx->config-> - rx_wakelock_timeout); - } - /* Remove SKB from internal tracking table before submitting * it to stack */ diff --git a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c index 69566634ca81..1e904283d636 100644 --- a/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c +++ b/drivers/staging/qcacld-3.0/core/hdd/src/wlan_hdd_wext.c @@ -3247,9 +3247,11 @@ static QDF_STATUS hdd_wlan_get_ibss_peer_info(struct hdd_adapter *adapter, qdf_mem_copy(mac_addr, pPeerInfo->peerInfoParams[0]. mac_addr, sizeof(mac_addr)); +#ifdef WLAN_DEBUG hdd_debug("PEER ADDR : %pM TxRate: %d Mbps RSSI: %d", mac_addr, (int)tx_rate, (int)pPeerInfo->peerInfoParams[0].rssi); +#endif } } else { hdd_warn("Warning: sme_request_ibss_peer_info Request failed"); diff --git a/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h b/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h index 9398a3c1b31f..3673050433da 100644 --- a/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h +++ b/drivers/staging/qcacld-3.0/core/mac/inc/mac_trace.h @@ -34,11 +34,11 @@ #define MAC_TRACE_GET_MODULE_ID(data) ((data >> 8) & 0xff) #define MAC_TRACE_GET_MSG_ID(data) (data & 0xffff) -#ifdef TRACE_RECORD - #define eLOG_NODROP_MISSED_BEACON_SCENARIO 0 #define eLOG_PROC_DEAUTH_FRAME_SCENARIO 1 +#ifdef TRACE_RECORD + void mac_trace(tpAniSirGlobal pMac, uint8_t code, uint16_t session, uint32_t data); void mac_trace_new(tpAniSirGlobal pMac, uint8_t module, uint8_t code, diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c index dc144c0c067d..7867aeb9812d 100644 --- a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_api.c @@ -2766,6 +2766,7 @@ void lim_update_lost_link_info(tpAniSirGlobal mac, tpPESession session, lim_sys_process_mmh_msg_api(mac, &mmh_msg, ePROT); } +#ifdef TRACE_RECORD QDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe) { QDF_STATUS status = QDF_STATUS_E_INVAL; @@ -2778,6 +2779,7 @@ QDF_STATUS pe_acquire_global_lock(tAniSirLim *psPe) } return status; } +#endif QDF_STATUS pe_release_global_lock(tAniSirLim *psPe) { diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c index a369d534266b..9559e4f94833 100644 --- a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_fils.c @@ -887,6 +887,11 @@ static QDF_STATUS lim_process_auth_wrapped_data(tpPESession pe_session, pe_err("invalid remaining len %d", remaining_len); } + + if (sizeof(hash) < auth_tag_len) { + pe_err("sizeof(hash) < auth_tag_len check failed"); + return QDF_STATUS_E_FAILURE; + } if (qdf_mem_cmp(wrapped_data, hash, auth_tag_len)) { pe_err("integratity check failed for auth, crypto %d", crypto); diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c index d370cf15c78e..eb4d617320d7 100644 --- a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_process_tdls.c @@ -176,7 +176,6 @@ enum tdls_peer_capability { #define TID_AC_VI 4 #define TID_AC_BK 1 -#ifdef WLAN_DEBUG static const uint8_t *lim_trace_tdls_action_string(uint8_t tdlsActionCode) { switch (tdlsActionCode) { @@ -193,7 +192,6 @@ static const uint8_t *lim_trace_tdls_action_string(uint8_t tdlsActionCode) } return (const uint8_t *)"UNKNOWN"; } -#endif /* * initialize TDLS setup list and related data structures. diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c index f71b37ca50a5..47a69b969577 100644 --- a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_send_management_frames.c @@ -5186,8 +5186,11 @@ void lim_send_mgmt_frame_tx(tpAniSirGlobal mac_ctx, void *packet; msg_len = mb_msg->msg_len - sizeof(*mb_msg); + +#ifdef WLAN_DEBUG pe_debug("sending fc->type: %d fc->subType: %d", fc->type, fc->subType); +#endif sme_session_id = mb_msg->session_id; diff --git a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h index 5b34ab2cb364..03c26701883b 100644 --- a/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h +++ b/drivers/staging/qcacld-3.0/core/mac/src/pe/lim/lim_utils.h @@ -742,10 +742,10 @@ void lim_diag_mgmt_rx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, static inline void lim_diag_event_report(tpAniSirGlobal pMac, uint16_t eventType, tpPESession pSessionEntry, uint16_t status, uint16_t reasonCode) {} -void lim_diag_mgmt_tx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, +static inline void lim_diag_mgmt_tx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, tpPESession session, uint16_t result_code, uint16_t reason_code) {} -void lim_diag_mgmt_rx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, +static inline void lim_diag_mgmt_rx_event_report(tpAniSirGlobal mac_ctx, void *mgmt_hdr, tpPESession session, uint16_t result_code, uint16_t reason_code) {} #endif /* FEATURE_WLAN_DIAG_SUPPORT */ diff --git a/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h index 78dfaf9706ab..11238b7a0c48 100644 --- a/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h +++ b/drivers/staging/qcacld-3.0/core/sme/inc/csr_internal.h @@ -200,7 +200,6 @@ enum csr_roam_stats_classtypes { eCsrMaxStats }; -#ifdef FEATURE_WLAN_DIAG_SUPPORT enum csr_diagwlan_status_eventsubtype { eCSR_WLAN_STATUS_CONNECT = 0, eCSR_WLAN_STATUS_DISCONNECT @@ -219,8 +218,6 @@ enum csr_diagwlan_status_eventreason { }; -#endif /* FEATURE_WLAN_DIAG_SUPPORT */ - struct csr_channel { uint8_t numChannels; uint8_t channelList[WNI_CFG_VALID_CHANNEL_LIST_LEN]; diff --git a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c index d4ec108e312f..46c1c8b59d6d 100644 --- a/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c +++ b/drivers/staging/qcacld-3.0/core/sme/src/common/sme_api.c @@ -5839,7 +5839,6 @@ QDF_STATUS sme_get_cfg_valid_channels(uint8_t *aValidChannels, return status; } -#ifdef WLAN_DEBUG static uint8_t *sme_reg_hint_to_str(const enum country_src src) { switch (src) { @@ -5859,7 +5858,6 @@ static uint8_t *sme_reg_hint_to_str(const enum country_src src) return "unknown"; } } -#endif void sme_set_cc_src(tHalHandle hHal, enum country_src cc_src) { diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c index 00743adc65df..e00dded741b7 100644 --- a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_roam.c @@ -7921,8 +7921,10 @@ static void csr_roam_process_start_bss_success(tpAniSirGlobal mac_ctx, tDot11fBeaconIEs *ies_ptr = NULL; tSirMacAddr bcast_mac = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; QDF_STATUS status; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR host_log_ibss_pkt_type *ibss_log; uint32_t bi; +#endif #ifdef FEATURE_WLAN_MCC_TO_SCC_SWITCH tSirSmeHTProfile *src_profile = NULL; tCsrRoamHTProfile *dst_profile = NULL; @@ -8703,7 +8705,9 @@ static bool csr_roam_process_results(tpAniSirGlobal mac_ctx, tSmeCmd *cmd, struct csr_roam_profile *profile = &cmd->u.roamCmd.roamProfile; eRoamCmdStatus roam_status; eCsrRoamResult roam_result; +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR host_log_ibss_pkt_type *ibss_log; +#endif tSirSmeStartBssRsp *start_bss_rsp = NULL; if (!session) { @@ -14012,6 +14016,7 @@ static QDF_STATUS csr_roam_start_wait_for_key_timer( if (csr_neighbor_roam_is_handoff_in_progress(pMac, pMac->roam.WaitForKeyTimerInfo. vdev_id)) { +#ifdef WLAN_DEBUG /* Disable heartbeat timer when hand-off is in progress */ sme_debug("disabling HB timer in state: %s sub-state: %s", mac_trace_get_neighbour_roam_state( @@ -14019,6 +14024,7 @@ static QDF_STATUS csr_roam_start_wait_for_key_timer( mac_trace_getcsr_roam_sub_state( pMac->roam.curSubState[pMac->roam. WaitForKeyTimerInfo.vdev_id])); +#endif cfg_set_int(pMac, WNI_CFG_HEART_BEAT_THRESHOLD, 0); } sme_debug("csrScanStartWaitForKeyTimer"); @@ -14034,7 +14040,6 @@ QDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac) tpCsrNeighborRoamControlInfo pNeighborRoamInfo = &pMac->roam.neighborRoamInfo[pMac->roam.WaitForKeyTimerInfo. vdev_id]; -#endif sme_debug("WaitForKey timer stopped in state: %s sub-state: %s", mac_trace_get_neighbour_roam_state(pNeighborRoamInfo-> @@ -14043,6 +14048,8 @@ QDF_STATUS csr_roam_stop_wait_for_key_timer(tpAniSirGlobal pMac) curSubState[pMac->roam. WaitForKeyTimerInfo. vdev_id])); +#endif + if (csr_neighbor_roam_is_handoff_in_progress(pMac, pMac->roam.WaitForKeyTimerInfo.vdev_id)) { /* diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c index eba4fcadbafd..26078a1e0368 100644 --- a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_api_scan.c @@ -741,6 +741,7 @@ void csr_clear_votes_for_country_info(tpAniSirGlobal pMac) sizeof(struct csr_votes11d) * CSR_MAX_NUM_COUNTRY_CODE); } +#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR /* caller allocated memory for pNumChn and pChnPowerInfo */ /* As input, *pNumChn has the size of the array of pChnPowerInfo */ /* Upon return, *pNumChn has the number of channels assigned. */ @@ -770,7 +771,6 @@ static void csr_get_channel_power_info(tpAniSirGlobal pMac, tDblLinkList *list, } -#ifdef FEATURE_WLAN_DIAG_SUPPORT_CSR static void csr_diag_apply_country_info(tpAniSirGlobal mac_ctx) { host_log_802_11d_pkt_type *p11dLog; diff --git a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c index 98f87613db95..5e0fc853d996 100644 --- a/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c +++ b/drivers/staging/qcacld-3.0/core/sme/src/csr/csr_neighbor_roam.c @@ -35,7 +35,6 @@ #include "mac_trace.h" #include "wlan_policy_mgr_api.h" -#ifdef WLAN_DEBUG static const char *lfr_get_config_item_string(uint8_t reason) { switch (reason) { @@ -49,7 +48,6 @@ static const char *lfr_get_config_item_string(uint8_t reason) return "unknown"; } } -#endif static void csr_neighbor_roam_reset_channel_info(tpCsrNeighborRoamChannelInfo rChInfo); diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index a40ec378e950..f695d10c4e1b 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c @@ -37,6 +37,7 @@ #include +#define USE_LMH_DEV 0 /* * Cooling state <-> CPUFreq frequency * @@ -300,7 +301,7 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, unsigned long clipped_freq = ULONG_MAX, floor_freq = 0; struct cpufreq_cooling_device *cpufreq_cdev; - if (event != CPUFREQ_INCOMPATIBLE) + if (event != CPUFREQ_THERMAL) return NOTIFY_DONE; mutex_lock(&cooling_list_lock); @@ -331,13 +332,36 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, * Similarly, if policy minimum set by the user is less than * the floor_frequency, then adjust the policy->min. */ - if (policy->max > clipped_freq || policy->min < floor_freq) - cpufreq_verify_within_limits(policy, floor_freq, clipped_freq); + cpufreq_verify_within_limits(policy, floor_freq, clipped_freq); mutex_unlock(&cooling_list_lock); return NOTIFY_OK; } +void cpu_limits_set_level(unsigned int cpu, unsigned int max_freq) +{ + struct cpufreq_cooling_device *cpufreq_cdev; + struct thermal_cooling_device *cdev; + unsigned int level; + + list_for_each_entry(cpufreq_cdev, &cpufreq_cdev_list, node) { + if (cpufreq_cdev->id == cpu) { + for (level = 0; level < cpufreq_cdev->max_level; level++) { + int target_freq = cpufreq_cdev->freq_table[level].frequency; + if (max_freq >= target_freq) { + cdev = cpufreq_cdev->cdev; + if (cdev) + cdev->ops->set_cur_state(cdev, level); + + break; + } + } + + break; + } + } +} + /** * update_freq_table() - Update the freq table with power numbers * @cpufreq_cdev: the cpufreq cooling device in which to update the table @@ -674,7 +698,7 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, /* Request state should be less than max_level */ if (WARN_ON(state > cpufreq_cdev->max_level)) - return -EINVAL; + state = cpufreq_cdev->max_level; /* Check if the old cooling action is same as new cooling action */ if (cpufreq_cdev->cpufreq_state == state) @@ -724,12 +748,18 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, * can handle the CPU freq mitigation, if not, notify cpufreq * framework. */ - if (cpufreq_cdev->plat_ops) { + if (USE_LMH_DEV && cpufreq_cdev->plat_ops) { if (cpufreq_cdev->plat_ops->ceil_limit) cpufreq_cdev->plat_ops->ceil_limit(cpu, clip_freq); + + get_online_cpus(); + cpufreq_update_policy(cpu); + put_online_cpus(); } else { + get_online_cpus(); cpufreq_update_policy(cpu); + put_online_cpus(); } return 0; @@ -1087,7 +1117,7 @@ __cpufreq_cooling_register(struct device_node *np, list_add(&cpufreq_cdev->node, &cpufreq_cdev_list); mutex_unlock(&cooling_list_lock); - if (first && !cpufreq_cdev->plat_ops) + if (first) cpufreq_register_notifier(&thermal_cpufreq_notifier_block, CPUFREQ_POLICY_NOTIFIER); if (!cpuhp_registered) { @@ -1280,10 +1310,9 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) if (last) { unregister_pm_notifier(&cpufreq_cooling_pm_nb); - if (!cpufreq_cdev->plat_ops) - cpufreq_unregister_notifier( - &thermal_cpufreq_notifier_block, - CPUFREQ_POLICY_NOTIFIER); + cpufreq_unregister_notifier( + &thermal_cpufreq_notifier_block, + CPUFREQ_POLICY_NOTIFIER); } thermal_cooling_device_unregister(cpufreq_cdev->cdev); diff --git a/drivers/thermal/msm-tsens.c b/drivers/thermal/msm-tsens.c index c1a52b104991..017c1e4ce571 100644 --- a/drivers/thermal/msm-tsens.c +++ b/drivers/thermal/msm-tsens.c @@ -259,7 +259,9 @@ int tsens_tm_probe(struct platform_device *pdev) { struct tsens_device *tmdev = NULL; int rc; +#ifdef CONFIG_IPC_LOGGING char tsens_name[40]; +#endif if (!(pdev->dev.of_node)) return -ENODEV; @@ -307,6 +309,7 @@ int tsens_tm_probe(struct platform_device *pdev) return rc; } +#ifdef CONFIG_IPC_LOGGING snprintf(tsens_name, sizeof(tsens_name), "tsens_%pa_0", &tmdev->phys_addr_tm); @@ -333,6 +336,7 @@ int tsens_tm_probe(struct platform_device *pdev) if (!tmdev->ipc_log2) pr_err("%s : unable to create IPC Logging 2 for tsens %pa", __func__, &tmdev->phys_addr_tm); +#endif list_add_tail(&tmdev->list, &tsens_device_list); platform_set_drvdata(pdev, tmdev); diff --git a/drivers/thermal/qcom/bcl_peripheral.c b/drivers/thermal/qcom/bcl_peripheral.c index ffc8760305a2..16108bb76920 100644 --- a/drivers/thermal/qcom/bcl_peripheral.c +++ b/drivers/thermal/qcom/bcl_peripheral.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2014-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2014-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -424,21 +424,15 @@ static irqreturn_t bcl_handle_ibat(int irq, void *data) { struct bcl_peripheral_data *perph_data = (struct bcl_peripheral_data *)data; + bool irq_enabled = false; mutex_lock(&perph_data->state_trans_lock); - if (!perph_data->irq_enabled) { - WARN_ON(1); - disable_irq_nosync(irq); - perph_data->irq_enabled = false; - goto exit_intr; - } + irq_enabled = perph_data->irq_enabled; mutex_unlock(&perph_data->state_trans_lock); - of_thermal_handle_trip(perph_data->tz_dev); - return IRQ_HANDLED; + if (irq_enabled) + of_thermal_handle_trip(perph_data->tz_dev); -exit_intr: - mutex_unlock(&perph_data->state_trans_lock); return IRQ_HANDLED; } @@ -446,21 +440,15 @@ static irqreturn_t bcl_handle_vbat(int irq, void *data) { struct bcl_peripheral_data *perph_data = (struct bcl_peripheral_data *)data; + bool irq_enabled = false; mutex_lock(&perph_data->state_trans_lock); - if (!perph_data->irq_enabled) { - WARN_ON(1); - disable_irq_nosync(irq); - perph_data->irq_enabled = false; - goto exit_intr; - } + irq_enabled = perph_data->irq_enabled; mutex_unlock(&perph_data->state_trans_lock); - of_thermal_handle_trip(perph_data->tz_dev); - return IRQ_HANDLED; + if (irq_enabled) + of_thermal_handle_trip(perph_data->tz_dev); -exit_intr: - mutex_unlock(&perph_data->state_trans_lock); return IRQ_HANDLED; } diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 891ed3b88271..8372198d921b 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c @@ -25,6 +25,11 @@ #include #include #include +#include + +#ifdef CONFIG_DRM +#include +#endif #define CREATE_TRACE_POINTS #include @@ -38,6 +43,8 @@ MODULE_LICENSE("GPL v2"); #define THERMAL_MAX_ACTIVE 16 +#define CPU_LIMITS_PARAM_NUM 2 + static DEFINE_IDA(thermal_tz_ida); static DEFINE_IDA(thermal_cdev_ida); @@ -56,6 +63,19 @@ static struct thermal_governor *def_governor; static struct workqueue_struct *thermal_passive_wq; +#ifdef CONFIG_DRM +struct screen_monitor { + struct notifier_block thermal_notifier; + int screen_state; /* 1: on; 0:off */ +}; + +struct screen_monitor sm; +#endif + +static atomic_t switch_mode = ATOMIC_INIT(-1); +static atomic_t temp_state = ATOMIC_INIT(0); +static char boost_buf[128]; + /* * Governor section: set of functions to handle thermal governors * @@ -941,6 +961,8 @@ static struct class thermal_class = { .dev_release = thermal_release, }; +static struct device thermal_message_dev; + static inline void print_bind_err_msg(struct thermal_zone_device *tz, struct thermal_cooling_device *cdev, int ret) @@ -1621,6 +1643,185 @@ static struct notifier_block thermal_pm_nb = { .notifier_call = thermal_pm_notify, }; +#ifdef CONFIG_DRM +static ssize_t +thermal_screen_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", sm.screen_state); +} + +static DEVICE_ATTR(screen_state, 0644, + thermal_screen_state_show, NULL); +#endif + +static ssize_t +thermal_sconfig_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&switch_mode)); +} + +static ssize_t +thermal_sconfig_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int val = -1; + + val = simple_strtol(buf, NULL, 10); + + atomic_set(&switch_mode, val); + + return len; +} + +static DEVICE_ATTR(sconfig, 0664, + thermal_sconfig_show, thermal_sconfig_store); + +static ssize_t +thermal_boost_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, boost_buf); +} + +static ssize_t +thermal_boost_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int ret; + ret = snprintf(boost_buf, PAGE_SIZE, buf); + return len; +} + +static DEVICE_ATTR(boost, 0644, + thermal_boost_show, thermal_boost_store); + +static ssize_t +thermal_temp_state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return snprintf(buf, PAGE_SIZE, "%d\n", atomic_read(&temp_state)); +} + +static ssize_t +thermal_temp_state_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + int val = -1; + + val = simple_strtol(buf, NULL, 10); + + atomic_set(&temp_state, val); + + return len; +} + +static DEVICE_ATTR(temp_state, 0664, + thermal_temp_state_show, thermal_temp_state_store); + +static ssize_t +cpu_limits_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return 0; +} + +static ssize_t +cpu_limits_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t len) +{ + unsigned int cpu; + unsigned int max; + + if (sscanf(buf, "cpu%u %u", &cpu, &max) != CPU_LIMITS_PARAM_NUM) { + pr_err("input param error, can not prase param\n"); + return -EINVAL; + } + + cpu_limits_set_level(cpu, max); + + return len; +} + +static DEVICE_ATTR(cpu_limits, 0664, + cpu_limits_show, cpu_limits_store); + +static int create_thermal_message_node(void) +{ + int ret = 0; + + thermal_message_dev.class = &thermal_class; + + dev_set_name(&thermal_message_dev, "thermal_message"); + ret = device_register(&thermal_message_dev); + if (!ret) { +#ifdef CONFIG_DRM + ret = sysfs_create_file(&thermal_message_dev.kobj, &dev_attr_screen_state.attr); + if (ret < 0) + pr_warn("Thermal: create batt message node failed\n"); +#endif + ret = sysfs_create_file(&thermal_message_dev.kobj, &dev_attr_sconfig.attr); + if (ret < 0) + pr_warn("Thermal: create sconfig node failed\n"); + + ret = sysfs_create_file(&thermal_message_dev.kobj, &dev_attr_boost.attr); + if (ret < 0) + pr_warn("Thermal: create boost node failed\n"); + + ret = sysfs_create_file(&thermal_message_dev.kobj, &dev_attr_temp_state.attr); + if (ret < 0) + pr_warn("Thermal: create temp state node failed\n"); + + ret = sysfs_create_file(&thermal_message_dev.kobj, &dev_attr_cpu_limits.attr); + if (ret < 0) + pr_warn("Thermal: create cpu limits node failed\n"); + } + + return ret; +} + +static void destroy_thermal_message_node(void) +{ + sysfs_remove_file(&thermal_message_dev.kobj, &dev_attr_cpu_limits.attr); + sysfs_remove_file(&thermal_message_dev.kobj, &dev_attr_temp_state.attr); + sysfs_remove_file(&thermal_message_dev.kobj, &dev_attr_boost.attr); + sysfs_remove_file(&thermal_message_dev.kobj, &dev_attr_sconfig.attr); +#ifdef CONFIG_DRM + sysfs_remove_file(&thermal_message_dev.kobj, &dev_attr_screen_state.attr); +#endif + device_unregister(&thermal_message_dev); +} + +#ifdef CONFIG_DRM +static int screen_state_for_thermal_callback(struct notifier_block *nb, unsigned long val, void *data) +{ + struct msm_drm_notifier *evdata = data; + unsigned int blank; + + if (val != MSM_DRM_EVENT_BLANK || !evdata || !evdata->data) + return 0; + + blank = *(int *)(evdata->data); + switch (blank) { + case MSM_DRM_BLANK_POWERDOWN: + sm.screen_state = 0; + pr_warn("%s: MSM_DRM_BLANK_POWERDOWN\n", __func__); + break; + case MSM_DRM_BLANK_UNBLANK: + sm.screen_state = 1; + pr_warn("%s: MSM_DRM_BLANK_UNBLANK\n", __func__); + break; + default: + break; + } + + sysfs_notify(&thermal_message_dev.kobj, NULL, "screen_state"); + + return NOTIFY_OK; +} +#endif + static int __init thermal_init(void) { int result; @@ -1652,6 +1853,18 @@ static int __init thermal_init(void) pr_warn("Thermal: Can not register suspend notifier, return %d\n", result); + result = create_thermal_message_node(); + if (result) + pr_warn("Thermal: create thermal message node failed, return %d\n", + result); + +#ifdef CONFIG_DRM + sm.thermal_notifier.notifier_call = screen_state_for_thermal_callback; + if (msm_drm_register_client(&sm.thermal_notifier) < 0) { + pr_warn("Thermal: register screen state callback failed\n"); + } +#endif + return 0; exit_zone_parse: @@ -1671,10 +1884,14 @@ static int __init thermal_init(void) static void thermal_exit(void) { +#ifdef CONFIG_DRM + msm_drm_unregister_client(&sm.thermal_notifier); +#endif unregister_pm_notifier(&thermal_pm_nb); of_thermal_destroy_zones(); destroy_workqueue(thermal_passive_wq); genetlink_exit(); + destroy_thermal_message_node(); class_unregister(&thermal_class); thermal_unregister_governors(); ida_destroy(&thermal_tz_ida); diff --git a/drivers/tty/serial/msm_geni_serial.c b/drivers/tty/serial/msm_geni_serial.c index c4aad4e02b72..70d96a5e8cfa 100644 --- a/drivers/tty/serial/msm_geni_serial.c +++ b/drivers/tty/serial/msm_geni_serial.c @@ -115,7 +115,7 @@ #define UART_CORE2X_VOTE (5000) #define UART_CONSOLE_CORE2X_VOTE (960) -#define WAKEBYTE_TIMEOUT_MSEC (2000) +#define WAKEBYTE_TIMEOUT_MSEC (100) #define WAIT_XFER_MAX_ITER (2) #define WAIT_XFER_MAX_TIMEOUT_US (10000) #define WAIT_XFER_MIN_TIMEOUT_US (9000) @@ -180,6 +180,7 @@ struct msm_geni_serial_port { struct msm_geni_serial_ver_info ver_info; u32 cur_tx_remaining; bool startup_in_progress; + struct mutex ioctl_mutex; }; static const struct uart_ops msm_geni_serial_pops; @@ -387,24 +388,28 @@ static int vote_clock_off(struct uart_port *uport) static int msm_geni_serial_ioctl(struct uart_port *uport, unsigned int cmd, unsigned long arg) { - int ret = -ENOIOCTLCMD; + struct msm_geni_serial_port *port = GET_DEV_PORT(uport); + int ret; + + mutex_lock(&port->ioctl_mutex); switch (cmd) { - case TIOCPMGET: { + case TIOCPMGET: ret = vote_clock_on(uport); break; - } - case TIOCPMPUT: { + case TIOCPMPUT: ret = vote_clock_off(uport); break; - } - case TIOCPMACT: { + case TIOCPMACT: ret = !pm_runtime_status_suspended(uport->dev); break; - } default: + ret = -ENOIOCTLCMD; break; } + + mutex_unlock(&port->ioctl_mutex); + return ret; } @@ -1746,11 +1751,6 @@ static void msm_geni_serial_shutdown(struct uart_port *uport) unsigned long flags; int ret; - if (!uart_console(uport)) { - msm_geni_serial_power_on(uport); - wait_for_transfers_inflight(uport); - } - disable_irq(uport->irq); free_irq(uport->irq, uport); spin_lock_irqsave(&uport->lock, flags); @@ -3037,6 +3037,7 @@ static int __init msm_geni_serial_init(void) msm_geni_serial_ports[i].uport.ops = &msm_geni_serial_pops; msm_geni_serial_ports[i].uport.flags = UPF_BOOT_AUTOCONF; msm_geni_serial_ports[i].uport.line = i; + mutex_init(&msm_geni_serial_ports[i].ioctl_mutex); } for (i = 0; i < GENI_UART_CONS_PORTS; i++) { @@ -3044,6 +3045,7 @@ static int __init msm_geni_serial_init(void) msm_geni_console_port.uport.ops = &msm_geni_console_pops; msm_geni_console_port.uport.flags = UPF_BOOT_AUTOCONF; msm_geni_console_port.uport.line = i; + mutex_init(&msm_geni_console_port.ioctl_mutex); } ret = console_register(&msm_geni_console_driver); diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index cbe1539d06b2..958a9c314351 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -38,6 +38,8 @@ #define USB_VENDOR_GENESYS_LOGIC 0x05e3 #define HUB_QUIRK_CHECK_PORT_AUTOSUSPEND 0x01 +int deny_new_usb __read_mostly = 0; + /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -4707,7 +4709,8 @@ hub_port_init(struct usb_hub *hub, struct usb_device *udev, int port1, /* notify HCD that we have a device connected and addressed */ if (hcd->driver->update_device) hcd->driver->update_device(hcd, udev); - hub_set_initial_usb2_lpm_policy(udev); + if (0) /*disable USB 2.0 Link PM to fix long time usb storage recognition issue*/ + hub_set_initial_usb2_lpm_policy(udev); fail: if (retval) { hub_port_disable(hub, port1, 0); @@ -4852,6 +4855,12 @@ static void hub_port_connect(struct usb_hub *hub, int port1, u16 portstatus, goto done; return; } + + if (deny_new_usb) { + dev_err(&port_dev->dev, "denied insert of USB device on port %d\n", port1); + goto done; + } + if (hub_is_superspeed(hub->hdev)) unit_load = 150; else diff --git a/drivers/usb/dwc3/dwc3-msm.c b/drivers/usb/dwc3/dwc3-msm.c index df51c6b21fe5..c7335823af3b 100644 --- a/drivers/usb/dwc3/dwc3-msm.c +++ b/drivers/usb/dwc3/dwc3-msm.c @@ -4517,8 +4517,10 @@ static int dwc3_msm_gadget_vbus_draw(struct dwc3_msm *mdwc, unsigned int mA) * bail out if suspend happened with float cable * connected */ + /* xiaomi charger driver need this current config float current, so remove this qcom default retuen feature. if (mA == 2) return 0; + */ if (!mA) pval.intval = -ETIMEDOUT; diff --git a/drivers/usb/gadget/configfs.c b/drivers/usb/gadget/configfs.c index 457e2b181f1c..bedbb651e644 100644 --- a/drivers/usb/gadget/configfs.c +++ b/drivers/usb/gadget/configfs.c @@ -8,6 +8,7 @@ #include "configfs.h" #include "u_f.h" #include "u_os_desc.h" +#include #ifdef CONFIG_USB_CONFIGFS_UEVENT #include @@ -1420,6 +1421,27 @@ static int configfs_composite_bind(struct usb_gadget *gadget, return ret; } +static int smblib_canncel_recheck(void) +{ + union power_supply_propval pval = {0}; + struct power_supply *usb_psy = NULL; + int rc = 0; + + if (!usb_psy) { + usb_psy = power_supply_get_by_name("usb"); + if (!usb_psy) { + pr_err("Could not get usb psy by canncel recheck\n"); + return -ENODEV; + } + } + + pval.intval = 0; + rc = power_supply_set_property(usb_psy, + POWER_SUPPLY_PROP_TYPE_RECHECK, &pval); + + return rc; +} + #ifdef CONFIG_USB_CONFIGFS_UEVENT static void android_work(struct work_struct *data) { @@ -1457,6 +1479,7 @@ static void android_work(struct work_struct *data) kobject_uevent_env(&gi->dev->kobj, KOBJ_CHANGE, configured); pr_info("%s: sent uevent %s\n", __func__, configured[0]); + smblib_canncel_recheck(); uevent_sent = true; } diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 5b2659a5c7eb..1d6cc835da2f 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -2290,11 +2290,11 @@ static int fsg_set_alt(struct usb_function *f, unsigned intf, unsigned alt) { struct fsg_dev *fsg = fsg_from_func(f); fsg->common->new_fsg = fsg; + raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); /* prevents usb LPM until thread runs to completion */ usb_gadget_autopm_get_async(fsg->common->gadget); - raise_exception(fsg->common, FSG_STATE_CONFIG_CHANGE); return USB_GADGET_DELAYED_STATUS; } diff --git a/drivers/usb/pd/policy_engine.c b/drivers/usb/pd/policy_engine.c index e11f6e387b37..ca0d4522683a 100644 --- a/drivers/usb/pd/policy_engine.c +++ b/drivers/usb/pd/policy_engine.c @@ -354,6 +354,10 @@ static void *usbpd_ipc_log; #define ID_HDR_PRODUCT_AMA 5 #define ID_HDR_PRODUCT_VPD 6 +#define PD_VBUS_MAX_VOLTAGE_LIMIT 9000000 +#define MAX_FIXED_PDO_MA 2000 +#define MAX_NON_COMPLIANT_PPS_UA 2000000 + static bool check_vsafe0v = true; module_param(check_vsafe0v, bool, 0600); @@ -451,6 +455,8 @@ struct usbpd { struct regulator *vconn; bool vbus_enabled; bool vconn_enabled; + u32 limit_pd_vbus; + u32 pd_vbus_max_limit; u8 tx_msgid[SOPII_MSG + 1]; u8 rx_msgid[SOPII_MSG + 1]; @@ -472,6 +478,14 @@ struct usbpd { bool has_dp; u16 ss_lane_svid; + /*for xiaomi verifed pd adapter*/ + u32 adapter_id; + u32 adapter_svid; + struct usbpd_vdm_data vdm_data; + struct usbpd_svid_handler svid_handler; + bool verifed; + int uvdm_state; + /* ext msg support */ bool send_get_src_cap_ext; u8 src_cap_ext_db[PD_SRC_CAP_EXT_DB_LEN]; @@ -812,6 +826,20 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua) pd->requested_voltage = PD_SRC_PDO_FIXED_VOLTAGE(pdo) * 50 * 1000; + + /* pd request uv will less than pd vbus max 9V for fixed pdos */ + if (pd->requested_voltage > PD_VBUS_MAX_VOLTAGE_LIMIT) + return -ENOTSUPP; + + /* + * set maxium allowed current for fixed pdo to 2A if request + * voltage is 9V, as we should limit charger to 18W for more safety + * both for charger and our device(such as charge ic inductor) + */ + if (pd->requested_voltage == PD_VBUS_MAX_VOLTAGE_LIMIT + && curr >= MAX_FIXED_PDO_MA) + curr = MAX_FIXED_PDO_MA; + pd->rdo = PD_RDO_FIXED(pdo_pos, 0, mismatch, 1, 1, curr / 10, max_current / 10); } else if (type == PD_SRC_PDO_TYPE_AUGMENTED) { @@ -824,6 +852,16 @@ static int pd_select_pdo(struct usbpd *pd, int pdo_pos, int uv, int ua) } curr = ua / 1000; + + /* if limit_pd_vbus is enabled, pd request uv will less than pd vbus max */ + if (pd->limit_pd_vbus && uv > pd->pd_vbus_max_limit) + uv = pd->pd_vbus_max_limit; + + if (curr == 0) { + ua = MAX_NON_COMPLIANT_PPS_UA; + curr = ua / 1000; + } + pd->requested_voltage = uv; pd->rdo = PD_RDO_AUGMENTED(pdo_pos, mismatch, 1, 1, uv / 20000, ua / 50000); @@ -1990,6 +2028,13 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) break; } + if (num_vdos != 0) { + for (i = 0; i < num_vdos; i++) { + pd->adapter_id = vdos[i] & 0xFFFF; + usbpd_info(&pd->dev, "pd->adapter_id:0x%x\n", pd->adapter_id); + } + } + pd->vdm_state = DISCOVERED_ID; usbpd_send_svdm(pd, USBPD_SID, USBPD_SVDM_DISCOVER_SVIDS, @@ -2055,6 +2100,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) if (svid) { usbpd_dbg(&pd->dev, "Discovered SVID: 0x%04x\n", svid); + pd->adapter_svid = svid; *psvid++ = svid; } } @@ -2098,6 +2144,7 @@ static void handle_vdm_rx(struct usbpd *pd, struct rx_msg *rx_msg) switch (cmd) { case USBPD_SVDM_DISCOVER_IDENTITY: case USBPD_SVDM_DISCOVER_SVIDS: + pd->uvdm_state = USBPD_UVDM_NAN_ACK; break; default: break; @@ -2517,6 +2564,8 @@ static void usbpd_sm(struct work_struct *w) pd->peer_usb_comm = pd->peer_pr_swap = pd->peer_dr_swap = false; memset(&pd->received_pdos, 0, sizeof(pd->received_pdos)); rx_msg_cleanup(pd); + pd->verifed = false; + pd->uvdm_state = USBPD_UVDM_DISCONNECT; power_supply_set_property(pd->usb_psy, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, &val); @@ -4373,6 +4422,216 @@ static ssize_t get_battery_status_show(struct device *dev, } static DEVICE_ATTR_RW(get_battery_status); +static ssize_t current_state_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct usbpd *pd = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%s", + usbpd_state_strings[pd->current_state]); +} +static DEVICE_ATTR_RO(current_state); + +static ssize_t usbpd_verifed_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct usbpd *pd = dev_get_drvdata(dev); + int val, ret; + + if (sscanf(buf, "%d\n", &val) != 1) { + pd->verifed = 0; + return -EINVAL; + } + usbpd_info(&pd->dev, "batteryd set usbpd verifyed :%d\n", val); + + pd->verifed = val; + + if (pd->verifed) { + ret = pd_send_msg(pd, MSG_GET_SOURCE_CAP, NULL, 0, SOP_MSG); + if (ret) { + usbpd_set_state(pd, PE_SEND_SOFT_RESET); + return size; + } + } + + return size; +} + +static ssize_t usbpd_verifed_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usbpd *pd = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%d\n", pd->verifed); +} +static DEVICE_ATTR_RW(usbpd_verifed); + +static ssize_t adapter_id_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usbpd *pd = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%08x", pd->adapter_id); +} +static DEVICE_ATTR_RO(adapter_id); + +static ssize_t adapter_svid_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usbpd *pd = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%04x", pd->adapter_svid); +} +static DEVICE_ATTR_RO(adapter_svid); +static ssize_t adapter_version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usbpd *pd = dev_get_drvdata(dev); + + return snprintf(buf, PAGE_SIZE, "%08x", pd->vdm_data.ta_version); +} +static DEVICE_ATTR_RO(adapter_version); + +static int StringToHex(char *str, unsigned char *out, unsigned int *outlen) +{ + char *p = str; + char high = 0, low = 0; + int tmplen = strlen(p), cnt = 0; + tmplen = strlen(p); + while (cnt < (tmplen / 2)) { + high = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48; + low = (*(++p) > '9' && ((*p <= 'F') || (*p <= 'f'))) ? *(p) - 48 - 7 : *(p) - 48; + out[cnt] = ((high & 0x0f) << 4 | (low & 0x0f)); + p++; + cnt++; + } + if (tmplen % 2 != 0) + out[cnt] = ((*p > '9') && ((*p <= 'F') || (*p <= 'f'))) ? *p - 48 - 7 : *p - 48; + + if (outlen != NULL) + *outlen = tmplen / 2 + tmplen % 2; + + return tmplen / 2 + tmplen % 2; +} + +#define BSWAP_32(x) \ + (u32)((((u32)(x) & 0xff000000) >> 24) | \ + (((u32)(x) & 0x00ff0000) >> 8) | \ + (((u32)(x) & 0x0000ff00) << 8) | \ + (((u32)(x) & 0x000000ff) << 24)) + +static void usbpd_sha256_bitswap32(unsigned int *array, int len) +{ + int i; + + for (i = 0; i < len; i++) { + array[i] = BSWAP_32(array[i]); + } +} + +static int usbpd_request_vdm_cmd(struct usbpd *pd, enum uvdm_state cmd, unsigned int *data) +{ + u32 vdm_hdr = 0; + int rc = 0; + struct usbpd_svid_handler *hdlr = &pd->svid_handler; + + vdm_hdr = VDM_HDR(hdlr->svid, USBPD_VDM_REQUEST, cmd); + + switch (cmd) { + case USBPD_UVDM_CHARGER_VERSION: + case USBPD_UVDM_CHARGER_TEMP: + case USBPD_UVDM_CHARGER_VOLTAGE: + rc = usbpd_send_vdm(pd, vdm_hdr, NULL, 0); + if (rc < 0) { + usbpd_err(&pd->dev, "failed to send %d\n", cmd); + return rc; + } + break; + case USBPD_UVDM_VERIFIED: + rc = usbpd_send_vdm(pd, vdm_hdr, data, USBPD_UVDM_VERIFIED_LEN); + if (rc < 0) { + usbpd_err(&pd->dev, "failed to send %d\n", cmd); + return rc; + } + break; + case USBPD_UVDM_SESSION_SEED: + case USBPD_UVDM_AUTHENTICATION: + usbpd_sha256_bitswap32(data, USBPD_UVDM_SS_LEN); + rc = usbpd_send_vdm(pd, vdm_hdr, data, USBPD_UVDM_SS_LEN); + if (rc < 0) { + usbpd_err(&pd->dev, "failed to send %d\n", cmd); + return rc; + } + break; + default: + usbpd_err(&pd->dev, "cmd:%d is not support\n", cmd); + break; + } + + return rc; +} + +static ssize_t request_vdm_cmd_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t size) +{ + struct usbpd *pd = dev_get_drvdata(dev); + int cmd, ret; + unsigned char buffer[64]; + unsigned char data[32]; + int count; + + ret = sscanf(buf, "%d,%s\n", &cmd, buffer); + + usbpd_dbg(&pd->dev, "%s:cmd:%d, buffer:%s\n", __func__, cmd, buffer); + + StringToHex(buffer, data, &count); + usbpd_request_vdm_cmd(pd, cmd, (unsigned int *)data); + + return size; +} + +static ssize_t request_vdm_cmd_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct usbpd *pd = dev_get_drvdata(dev); + int i; + char data[16], str_buf[128] = {0}; + int cmd = pd->uvdm_state; + + switch (cmd) { + case USBPD_UVDM_CHARGER_VERSION: + return snprintf(buf, PAGE_SIZE, "%d,%x", cmd, pd->vdm_data.ta_version); + break; + case USBPD_UVDM_CHARGER_TEMP: + return snprintf(buf, PAGE_SIZE, "%d,%d", cmd, pd->vdm_data.ta_temp); + break; + case USBPD_UVDM_CHARGER_VOLTAGE: + return snprintf(buf, PAGE_SIZE, "%d,%d", cmd, pd->vdm_data.ta_voltage); + break; + case USBPD_UVDM_SESSION_SEED: + case USBPD_UVDM_CONNECT: + case USBPD_UVDM_DISCONNECT: + case USBPD_UVDM_VERIFIED: + case USBPD_UVDM_NAN_ACK: + return snprintf(buf, PAGE_SIZE, "%d,Null", cmd); + break; + case USBPD_UVDM_AUTHENTICATION: + for (i = 0; i < USBPD_UVDM_SS_LEN; i++) { + memset(data, 0, sizeof(data)); + snprintf(data, sizeof(data), "%08lx", pd->vdm_data.digest[i]); + strlcat(str_buf, data, sizeof(str_buf)); + } + return snprintf(buf, PAGE_SIZE, "%d,%s", cmd, str_buf); + break; + default: + usbpd_err(&pd->dev, "feedbak cmd:%d is not support\n", cmd); + break; + } + return snprintf(buf, PAGE_SIZE, "%d,%s", cmd, str_buf); + +} +static DEVICE_ATTR_RW(request_vdm_cmd); + static struct attribute *usbpd_attrs[] = { &dev_attr_contract.attr, &dev_attr_initial_pr.attr, @@ -4397,6 +4656,12 @@ static struct attribute *usbpd_attrs[] = { &dev_attr_get_pps_status.attr, &dev_attr_get_battery_cap.attr, &dev_attr_get_battery_status.attr, + &dev_attr_request_vdm_cmd.attr, + &dev_attr_current_state.attr, + &dev_attr_adapter_id.attr, + &dev_attr_adapter_svid.attr, + &dev_attr_adapter_version.attr, + &dev_attr_usbpd_verifed.attr, NULL, }; ATTRIBUTE_GROUPS(usbpd); @@ -4467,6 +4732,108 @@ struct usbpd *devm_usbpd_get_by_phandle(struct device *dev, const char *phandle) } EXPORT_SYMBOL(devm_usbpd_get_by_phandle); +static void usbpd_mi_connect_cb(struct usbpd_svid_handler *hdlr, + bool peer_usb_comm) +{ + struct usbpd *pd; + + pd = container_of(hdlr, struct usbpd, svid_handler); + if(!pd) { + pr_err("get_usbpd phandle failed\n"); + return; + } + + pr_debug("peer_usb_comm: %d\n", peer_usb_comm); +// pd->dp_usbpd.base.peer_usb_comm = peer_usb_comm; + + pd->uvdm_state = USBPD_UVDM_CONNECT; + usbpd_info(&pd->dev, "hdlr->svid:%x has connect\n", hdlr->svid); + + return; +} + +static void usbpd_mi_disconnect_cb(struct usbpd_svid_handler *hdlr) +{ + struct usbpd *pd; + + pd = container_of(hdlr, struct usbpd, svid_handler); + + pd->adapter_id = 0; + pd->adapter_svid = 0; + pd->vdm_data.ta_version = 0; + pd->uvdm_state = USBPD_UVDM_DISCONNECT; + usbpd_info(&pd->dev, "hdlr->svid:%x has disconnect\n", hdlr->svid); + + return; +} + +static void usbpd_mi_vdm_received_cb(struct usbpd_svid_handler *hdlr, u32 vdm_hdr, + const u32 *vdos, int num_vdos) +{ + struct usbpd *pd; + int i, cmd; + int usb_current, usb_voltage, r_cable; + union power_supply_propval val = {0}; + int ret; + + pd = container_of(hdlr, struct usbpd, svid_handler); + cmd = UVDM_HDR_CMD(vdm_hdr); + + usbpd_dbg(&pd->dev, "hdlr->svid:0x%x, vdm_hdr:0x%x, num_vdos:%d, cmd:%d\n", + hdlr->svid, vdm_hdr, num_vdos); + + switch (cmd) { + case USBPD_UVDM_CHARGER_VERSION: + pd->vdm_data.ta_version = vdos[0]; + usbpd_dbg(&pd->dev, "ta_version:%x\n", pd->vdm_data.ta_version); + break; + case USBPD_UVDM_CHARGER_TEMP: + pd->vdm_data.ta_temp = (vdos[0] & 0xFFFF) * 10; + usbpd_dbg(&pd->dev, "pd->vdm_data.ta_temp:%d\n", pd->vdm_data.ta_temp); + break; + case USBPD_UVDM_CHARGER_VOLTAGE: + pd->vdm_data.ta_voltage = (vdos[0] & 0xFFFF) * 10; + pd->vdm_data.ta_voltage *= 1000; /*V->mV*/ + usbpd_dbg(&pd->dev, "ta_voltage:%d\n", pd->vdm_data.ta_voltage); + + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_VOLTAGE_NOW, &val); + if (ret) { + usbpd_err(&pd->dev, "failed to get usb voltage now\n"); + break; + } + usb_voltage = val.intval; + usbpd_dbg(&pd->dev, "usb voltage now:%d\n", usb_voltage); + ret = power_supply_get_property(pd->usb_psy, + POWER_SUPPLY_PROP_INPUT_CURRENT_NOW, &val); + if (ret) { + usbpd_err(&pd->dev, "failed to get usb current now\n"); + break; + } + usb_current = val.intval / 1000; + usbpd_dbg(&pd->dev, "usb current now:%d\n", usb_current); + + r_cable = (pd->vdm_data.ta_voltage - usb_voltage) / usb_current; + usbpd_dbg(&pd->dev, "usb r_cable now:%dmohm\n", r_cable); + break; + case USBPD_UVDM_SESSION_SEED: + for (i = 0; i < USBPD_UVDM_SS_LEN; i++) { + pd->vdm_data.s_secert[i] = vdos[i]; + usbpd_dbg(&pd->dev, "usbpd s_secert vdos[%d]=0x%x", i, vdos[i]); + } + break; + case USBPD_UVDM_AUTHENTICATION: + for (i = 0; i < USBPD_UVDM_SS_LEN; i++) { + pd->vdm_data.digest[i] = vdos[i]; + usbpd_dbg(&pd->dev, "usbpd digest[%d]=0x%x", i, vdos[i]); + } + break; + default: + break; + } + pd->uvdm_state = cmd; +} + static void usbpd_release(struct device *dev) { struct usbpd *pd = container_of(dev, struct usbpd, dev); @@ -4491,6 +4858,13 @@ struct usbpd *usbpd_create(struct device *parent) int ret; struct usbpd *pd; union power_supply_propval val = {0}; + struct usbpd_svid_handler svid_handler = { + .svid = USB_PD_MI_SVID, + .vdm_received = &usbpd_mi_vdm_received_cb, + .connect = &usbpd_mi_connect_cb, + .svdm_received = NULL, + .disconnect = &usbpd_mi_disconnect_cb, + }; pd = kzalloc(sizeof(*pd), GFP_KERNEL); if (!pd) @@ -4576,6 +4950,34 @@ struct usbpd *usbpd_create(struct device *parent) extcon_set_property_capability(pd->extcon, EXTCON_USB_HOST, EXTCON_PROP_USB_SS); + pd->vbus = devm_regulator_get(parent, "vbus"); + if (IS_ERR(pd->vbus)) { + ret = PTR_ERR(pd->vbus); + goto put_psy; + } + + pd->vconn = devm_regulator_get(parent, "vconn"); + if (IS_ERR(pd->vconn)) { + ret = PTR_ERR(pd->vconn); + goto put_psy; + } + + ret = of_property_read_u32(parent->of_node, "mi,limit_pd_vbus", + &pd->limit_pd_vbus); + if (ret) { + usbpd_err(&pd->dev, "failed to read pd vbus limit\n"); + pd->limit_pd_vbus = false; + } + + if (pd->limit_pd_vbus) { + ret = of_property_read_u32(parent->of_node, "mi,pd_vbus_max_limit", + &pd->pd_vbus_max_limit); + if (ret) { + usbpd_err(&pd->dev, "failed to read pd vbus max limit\n"); + pd->pd_vbus_max_limit = PD_VBUS_MAX_VOLTAGE_LIMIT; + } + } + pd->num_sink_caps = device_property_read_u32_array(parent, "qcom,default-sink-caps", NULL, 0); if (pd->num_sink_caps > 0) { @@ -4660,6 +5062,12 @@ struct usbpd *usbpd_create(struct device *parent) if (ret) goto del_inst; + pd->svid_handler = svid_handler; + ret = usbpd_register_svid(pd, &pd->svid_handler); + if (ret) { + usbpd_err(&pd->dev, "usbpd registration failed\n"); + } + /* force read initial power_supply values */ psy_changed(&pd->psy_nb, PSY_EVENT_PROP_CHANGED, pd->usb_psy); diff --git a/drivers/usb/pd/usbpd.h b/drivers/usb/pd/usbpd.h index 5c7c5cdf4c7d..79fa97e2f627 100644 --- a/drivers/usb/pd/usbpd.h +++ b/drivers/usb/pd/usbpd.h @@ -110,4 +110,38 @@ static inline void pd_phy_close(void) { } #endif + +enum uvdm_state { + USBPD_UVDM_DISCONNECT, + USBPD_UVDM_CHARGER_VERSION, + USBPD_UVDM_CHARGER_VOLTAGE, + USBPD_UVDM_CHARGER_TEMP, + USBPD_UVDM_SESSION_SEED, + USBPD_UVDM_AUTHENTICATION, + USBPD_UVDM_VERIFIED, + USBPD_UVDM_CONNECT, + USBPD_UVDM_NAN_ACK, +}; + +#define USB_PD_MI_SVID 0x2717 +#define USBPD_UVDM_SS_LEN 4 +#define USBPD_UVDM_VERIFIED_LEN 1 + +#define VDM_HDR(svid, cmd0, cmd1) \ + (((svid) << 16) | (0 << 15) | ((cmd0) << 8) \ + | (cmd1)) +#define UVDM_HDR_CMD(hdr) ((hdr) & 0xFF) + +#define USBPD_VDM_RANDOM_NUM 4 +#define USBPD_VDM_REQUEST 0x1 +#define USBPD_ACK 0x2 + +struct usbpd_vdm_data { + int ta_version; + int ta_temp; + int ta_voltage; + unsigned long s_secert[USBPD_UVDM_SS_LEN]; + unsigned long digest[USBPD_UVDM_SS_LEN]; +}; + #endif /* _USBPD_H */ diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig index 298ce75a2178..8f7df63fab38 100644 --- a/drivers/video/backlight/Kconfig +++ b/drivers/video/backlight/Kconfig @@ -15,7 +15,7 @@ if BACKLIGHT_LCD_SUPPORT # config LCD_CLASS_DEVICE tristate "Lowlevel LCD controls" - default m + default n help This framework adds support for low-level control of LCD. Some framebuffer devices connect to platform-specific LCD modules @@ -106,7 +106,7 @@ config LCD_TOSA config LCD_HP700 tristate "HP Jornada 700 series LCD Driver" depends on SA1100_JORNADA720_SSP && !PREEMPT - default y + default n help If you have an HP Jornada 700 series handheld (710/720/728) say Y to enable LCD control driver. @@ -191,7 +191,7 @@ config BACKLIGHT_EP93XX config BACKLIGHT_GENERIC tristate "Generic (aka Sharp Corgi) Backlight Driver" - default y + default n help Say y to enable the generic platform backlight driver previously known as the Corgi backlight driver. If you have a Sharp Zaurus @@ -200,7 +200,7 @@ config BACKLIGHT_GENERIC config BACKLIGHT_IPAQ_MICRO tristate "iPAQ microcontroller backlight driver" depends on MFD_IPAQ_MICRO - default y + default n help Say y to enable the backlight driver for Compaq iPAQ handheld computers. Say yes if you have one of the h3100/h3600/h3700 @@ -221,7 +221,7 @@ config BACKLIGHT_LM3533 config BACKLIGHT_LOCOMO tristate "Sharp LOCOMO LCD/Backlight Driver" depends on SHARP_LOCOMO - default y + default n help If you have a Sharp Zaurus SL-5500 (Collie) or SL-5600 (Poodle) say y to enable the LCD/backlight driver. @@ -229,7 +229,7 @@ config BACKLIGHT_LOCOMO config BACKLIGHT_OMAP1 tristate "OMAP1 PWL-based LCD Backlight" depends on ARCH_OMAP1 - default y + default n help This driver controls the LCD backlight level and power for the PWL module of OMAP1 processors. Say Y if your board @@ -238,7 +238,7 @@ config BACKLIGHT_OMAP1 config BACKLIGHT_HP680 tristate "HP Jornada 680 Backlight Driver" depends on SH_HP6XX - default y + default n help If you have a HP Jornada 680, say y to enable the backlight driver. @@ -246,7 +246,7 @@ config BACKLIGHT_HP680 config BACKLIGHT_HP700 tristate "HP Jornada 700 series Backlight Driver" depends on SA1100_JORNADA720_SSP && !PREEMPT - default y + default n help If you have an HP Jornada 700 series, say Y to include backlight control driver. diff --git a/firmware/Makefile b/firmware/Makefile index 168094a3fae7..7aff517ffc41 100644 --- a/firmware/Makefile +++ b/firmware/Makefile @@ -10,6 +10,29 @@ fwabs := $(addprefix $(srctree)/,$(filter-out /%,$(fwdir)))$(filter /%,$(fwdir)) fw-external-y := $(subst $(quote),,$(CONFIG_EXTRA_FIRMWARE)) +# There are three cases to care about: +# 1. Building kernel with CONFIG_FIRMWARE_IN_KERNEL=y -- $(fw-shipped-y) should +# include the firmware files to include, according to .config +# 2. 'make modules_install', which will install firmware for modules, and +# _also_ for the in-kernel drivers when CONFIG_FIRMWARE_IN_KERNEL=n +# 3. 'make firmware_install', which installs all firmware, unconditionally. + +# For the former two cases we want $(fw-shipped-y) and $(fw-shipped-m) to be +# accurate. In the latter case it doesn't matter -- it'll use $(fw-shipped-all). +# But be aware that the config file might not be included at all. +fw-shipped-$(CONFIG_TOUCHSCREEN_ST_FTS_V521) += st_fts_f1.ftb + +fw-shipped-all := $(fw-shipped-y) $(fw-shipped-m) $(fw-shipped-) + +quiet_cmd_ihex = IHEX $@ + cmd_ihex = $(OBJCOPY) -Iihex -Obinary $< $@ + +quiet_cmd_ihex2fw = IHEX2FW $@ + cmd_ihex2fw = $(objtree)/$(obj)/ihex2fw $< $@ + +quiet_cmd_h16tofw = H16TOFW $@ + cmd_h16tofw = $(objtree)/$(obj)/ihex2fw -w $< $@ + quiet_cmd_fwbin = MK_FW $@ cmd_fwbin = FWNAME="$(patsubst firmware/%.gen.S,%,$@)"; \ FWSTR="$(subst /,_,$(subst .,_,$(subst -,_,$(patsubst \ @@ -42,14 +65,46 @@ wordsize_deps := $(wildcard include/config/64bit.h include/config/32bit.h \ include/config/x86_32.h include/config/x86_64.h \ firmware/Makefile) +$(patsubst %,$(obj)/%.gen.S, $(fw-shipped-y)): %: $(wordsize_deps) + $(call cmd,fwbin,$(patsubst %.gen.S,%,$@)) $(patsubst %,$(obj)/%.gen.S, $(fw-external-y)): %: $(wordsize_deps) \ include/config/extra/firmware/dir.h $(call cmd,fwbin,$(fwabs)/$(patsubst $(obj)/%.gen.S,%,$@)) # The .o files depend on the binaries directly; the .S files don't. +$(patsubst %,$(obj)/%.gen.o, $(fw-shipped-y)): %.gen.o: % $(patsubst %,$(obj)/%.gen.o, $(fw-external-y)): $(obj)/%.gen.o: $(fwdir)/% +# .ihex is used just as a simple way to hold binary files in a source tree +# where binaries are frowned upon. They are directly converted with objcopy. +$(obj)/%: $(obj)/%.ihex + $(call cmd,ihex) + +# Don't depend on ihex2fw if we're installing and it already exists. +# Putting it after | in the dependencies doesn't seem sufficient when +# we're installing after a cross-compile, because ihex2fw has dependencies +# on stuff like /usr/lib/gcc/ppc64-redhat-linux/4.3.0/include/stddef.h and +# thus wants to be rebuilt. Which it can't be, if the prebuilt kernel tree +# is exported read-only for someone to run 'make install'. +ifeq ($(INSTALL):$(wildcard $(obj)/ihex2fw),install:$(obj)/ihex2fw) +ihex2fw_dep := +else +ihex2fw_dep := $(obj)/ihex2fw +endif + +# .HEX is also Intel HEX, but where the offset and length in each record +# is actually meaningful, because the firmware has to be loaded in a certain +# order rather than as a single binary blob. Thus, we convert them into our +# more compact binary representation of ihex records () +$(obj)/%.fw: $(obj)/%.HEX $(ihex2fw_dep) + $(call cmd,ihex2fw) + +# .H16 is our own modified form of Intel HEX, with 16-bit length for records. +$(obj)/%.fw: $(obj)/%.H16 $(ihex2fw_dep) + $(call cmd,h16tofw) + obj-y += $(patsubst %,%.gen.o, $(fw-external-y)) +obj-$(CONFIG_FIRMWARE_IN_KERNEL) += $(patsubst %,%.gen.o, $(fw-shipped-y)) ifeq ($(KBUILD_SRC),) # Makefile.build only creates subdirectories for O= builds, but external @@ -57,8 +112,11 @@ ifeq ($(KBUILD_SRC),) _dummy := $(foreach d,$(addprefix $(obj)/,$(dir $(fw-external-y))), $(shell [ -d $(d) ] || mkdir -p $(d))) endif -targets := $(patsubst $(obj)/%,%, \ - $(shell find $(obj) -name \*.gen.S 2>/dev/null)) +# Remove .S files and binaries created from ihex +# (during 'make clean' .config isn't included so they're all in $(fw-shipped-)) +targets := $(fw-shipped-) $(patsubst $(obj)/%,%, \ + $(shell find $(obj) -name \*.gen.S 2>/dev/null)) + # Without this, built-in.o won't be created when it's empty, and the # final vmlinux link will fail. obj- := dummy diff --git a/firmware/st_fts_f1.ftb.ihex b/firmware/st_fts_f1.ftb.ihex new file mode 100644 index 000000000000..c48dd0ce7f32 --- /dev/null +++ b/firmware/st_fts_f1.ftb.ihex @@ -0,0 +1,6816 @@ +:1000000055AA55AA01000000363900006022000000 +:10001000600000003E00000037000000000000000B +:100020000000000037F1000000000000B09D01005A +:10003000E00B0000000000000000000037A8894825 +:100040001FBCB9DE6B670000E04346219498FFFFB8 +:1000500000041000E101000039020000530200001A +:100060006D02000087020000A102000000000000F5 +:10007000000000000000000000000000F76D01001B +:10008000FF6D010000000000BB020000076E0100D0 +:100090000F6E01001B6E0100276E0100336E010020 +:1000A0003F6E01004B6E0100576E0100636E010050 +:1000B0006F6E0100C90200007B6E0100876E0100B7 +:1000C000936E01009B6E0100A36E0100AB6E0100F8 +:1000D000B76E0100BF6E0100C76E01000000000096 +:1000E000000000000000000000000000CF6E0100D2 +:1000F000D76E010000000000DF6E0100000000006C +:1001000000000000000000000000000000000000EF +:10011000600060220000FFFF0000000000000000FF +:1001200000000000000000000000000000000000CF +:1001300000F002F800F068F80AA090E8000C824491 +:100140008344AAF10107DA4501D100F05DF8AFF26E +:10015000090EBAE80F0013F0010F18BFFB1A43F0A5 +:1001600001031847F09B0100209C01000A444FF056 +:10017000000C10F8013B13F0070408BF10F8014B06 +:100180001D1108BF10F8015B641E05D010F8016B4B +:10019000641E01F8016BF9D113F0080F1EBF10F8AF +:1001A000014BAD1C0C1B09D16D1E58BF01F801CBD2 +:1001B000FAD505E014F8016B01F8016B6D1EF9D555 +:1001C0009142D6D370470000103A24BF78C878C156 +:1001D000FAD8520724BF30C830C144BF04680C604D +:1001E000704700000023002400250026103A28BF95 +:1001F00078C1FBD8520728BF30C148BF0B60704799 +:100200001FB51FBD10B510BDDFF80CD0FFF7F8FF0C +:1002100016F090FE19F00CF90004100003B4FFF77B +:10022000F1FF03BC19F00EF940BA7047C0BA70472D +:1002300012481349A1EB00014FF0200391FBF3F2A8 +:1002400002FB13114FF0CC334FF0CC344FF0CC35D0 +:100250004FF0CC364FF0CC374FF0CC384FF0CC3994 +:100260004FF0CC3AA0E8F807013AFBD119B140F8B9 +:1002700004AB0439FBD10348004700000000100024 +:1002800000041000E10000001EF0040F0CBFEFF3AB +:100290000880EFF309804FF001014FF0000212F0E7 +:1002A0004BB81EF0040F0CBFEFF30880EFF309808A +:1002B0004FF002014FF0000212F03EB81EF0040FA2 +:1002C0000CBFEFF30880EFF309804FF003014FF00C +:1002D000000212F031B81EF0040F0CBFEFF30880DB +:1002E000EFF309804FF004014FF0000212F024B840 +:1002F0001EF0040F0CBFEFF30880EFF309804FF0FE +:1003000005014FF0000212F017B800B516F094FD89 +:100310005DF804EB00F032B81EF0040F0CBFEFF3F1 +:100320000880EFF309804FF006014FF0000212F051 +:1003300003B800000A484FF0FF0101704FF00000C1 +:1003400080F311884FF0000080F3098805484FF0D2 +:100350000201017062B604484FF08051016070479D +:1003600022ED00E04408100004ED00E002484FF0E8 +:10037000805101607047000004ED00E04FF0200064 +:1003800080F31188EFF3098098B112480068124990 +:100390000968884217D0EFF309800E49096820E9FF +:1003A000F00F886000B50B48006816F059FE5DF844 +:1003B00004EB084808490A68026000688168B1E8EF +:1003C000F00F81F309884EF0040E4FF0000080F327 +:1003D00011887047480810004C081000EFF3118096 +:1003E0004FF0200181F31188704700004FF00000AA +:1003F00080F311887047000062B6704772B670478C +:10040000401EFDD17047000010B501464022FC4857 +:1004100018F014FF0121BDE81040002016F059BE6D +:1004200038B50446F748F64D2060204616F0C5FA68 +:1004300000226B460121104616F094FE0121002097 +:1004400016F073FE2878002802D011F0CCFFECE7FC +:1004500038BD2DE9F047DFF8B08382460127D8F890 +:100460000000EA4D90F8314010F8301F90F831004C +:100470004C4300F003008740A100284618F03AFFE3 +:100480000026DFF87C9312E0DD484030FFF7C8FF1C +:100490000020D9F8081007E055F8202031F9103075 +:1004A0001A4445F82020401CA042F5DB761CBE42D1 +:1004B000EADB40460AE000BF026855F8241092F8D3 +:1004C000612002F0030211412AF81410641EF3D2D5 +:1004D000BDE8F0872DE9F04FDFF82CB34FF00109AC +:1004E000CA4EDBF80000A7B090F8611090F83140D8 +:1004F000C1F3810890F8305009FA08FA60198100B8 +:1005000006EB8407304618F0F5FEBD48403016F083 +:100510002FFABB49403181F80690DBF8000090F8D3 +:100520006000820701D581F80490C00703D0B44869 +:100530004030FFF775FF00202BE0B1484030FFF757 +:100540006FFFDFF8BCB2620006A8DBF8181018F0E5 +:1005500030FE6A0011A8DBF81C1018F02AFE2046B5 +:1005600006A906E056F8202031F910301A4446F862 +:100570002020401EF6D2284611A906E057F8202078 +:1005800031F910301A4447F82020401EF6D209F104 +:10059000010081465045D0DB9D4905E056F8240016 +:1005A00040FA08F021F81400641EF7D2994905E0DA +:1005B00057F8250040FA08F021F815006D1EF7D213 +:1005C00027B0BDE8F08F2DE9F04FDFF83CB24FF0D7 +:1005D00001098E4EDBF80000A7B090F8621090F889 +:1005E000314001F0030890F8305009FA08FA601918 +:1005F000810006EB8407304618F07CFE80484030CE +:1006000016F0B6F97E49403181F80B90DBF8000016 +:1006100090F86000020701D581F80490C00603D568 +:1006200077484030FFF7FCFE00202CE07448403053 +:10063000FFF7F6FEDFF8C8B1620006A8DBF8341059 +:1006400018F0B7FD6A0011A8DBF8381018F0B1FDFA +:10065000204606A907E000BF56F8202031F91030E7 +:100660001A4446F82020401EF6D2284611A906E07A +:1006700057F8202031F910301A4447F82020401E46 +:10068000F6D209F1010081465045CFDB624905E011 +:1006900056F8240040FA08F021F81400641EF7D23E +:1006A0005E4905E057F8250040FA08F021F81500EA +:1006B0006D1EF7D284E72DE9F84F534D04462868A4 +:1006C00090F8311090F8300001FB00F84C484030B1 +:1006D00016F04EF94A4801264030012C067106D129 +:1006E000296891F87010090701D404210171286864 +:1006F000AB4600F5F97990F8611001F003018E40E6 +:100700004749002491F803A02AE000BF444819F8A3 +:1007100004100025C170434904FB08F001EB4007B9 +:100720004FEA4800009018E035484030FFF778FE67 +:10073000334881680DB140460CE03846009A18F005 +:1007400038FD09E037F9102031F910301A44521001 +:1007500027F81020401EF5D26D1CB542E4DB641C66 +:10076000DBF8000090F8F10100F00300401CA0420B +:10077000CCD82B4981F803A0BDE8F88F2DE9F04FC4 +:10078000214D85B0296891F8319091F83010009191 +:1007900009FB01F002901A48403016F0E9F81848B9 +:1007A0000124403084710471C471286890F860009D +:1007B000C00703D012484030FFF732FE28684FF0E0 +:1007C000000B90F8612000F5F97002F0030104FAC3 +:1007D00001FAC2F38102124904FA02F20192C978C5 +:1007E0005C46CDE903016DE00398015D0C48C170E2 +:1007F00002980C49604301EB400600255FE00000D1 +:1008000068081000B90300000407100070641000AD +:10081000006F01202A6F0120766F0120A06F012058 +:100820004007100010560120E248FFF7F9FDE148AB +:100830004038D0E90631876888462DB101998B454B +:1008400030DA4846DC491BE04FEA49021946DA48EB +:1008500018F0AFFC009841464200D84818F0A9FCB7 +:10086000029839464200304618F0A3FC26E000BF4B +:1008700031F9102033F910C06244521021F81020D1 +:10088000401EF5D2CD49009808E000BF31F9103084 +:1008900038F910201A44521021F81020401EF5D2C9 +:1008A0000BF1010B029807E036F9102037F9101010 +:1008B0001144491026F81010401EF5D26D1C554504 +:1008C000B2DB641CBE48006890F8F10100F0030040 +:1008D000401CA04288D801998B452CDAB5480021EC +:1008E0000C4601710199A1EB0B0522E0B148FFF71D +:1008F00097FDB048B0494038D0E90623484607E0A4 +:1009000031F9106032F910703E44761021F8106011 +:10091000401EF5D2A949009808E000BF31F9102027 +:1009200033F910603244521021F81020401EF5D2E5 +:10093000641CA542DADCA3490498C87005B040E6FF +:100940002DE9FF5FDFF878829F4FD8F8000090F81C +:10095000314090F8305007EB840A6019810004FBA5 +:1009600005FB0AEB8506384618F0C4FC4FEA8B01FC +:10097000304618F0BFFC8F4815F0FAFF8D494FF054 +:10098000010981F8069081F80490D8F8000090F8E9 +:100990006000C00702D00846FFF742FDD8F800000B +:1009A00090F86100C0F38101029100F0030103910E +:1009B0000299484609FA01F90399884001900020FC +:1009C00031E07C48FFF72CFD7A484038D0E9063208 +:1009D0008168204607E000BF57F820C033F9108037 +:1009E000C44447F820C0401EF6D2284607E000BFA6 +:1009F0005AF8203032F910C09C444AF820C0401EFA +:100A0000F6D2DDE9000290420BDA584607E000BF5B +:100A100056F8202031F910301A4446F82020401EA4 +:100A2000F6D20098401C00904845CADB0198484522 +:100A30001DDD60480021884681710198A0EB0909FD +:100A400013E05C48FFF7ECFC5A4840388168584690 +:100A500007E000BF56F8202031F910301A4446F85C +:100A60002020401EF6D208F10108C145E9DC5249B8 +:100A700006E000BF57F82400029A104121F8140044 +:100A8000641EF7D24D4905E05AF82500029A10413C +:100A900021F815006D1EF7D258464C4A06E000BFFB +:100AA00056F82010039B194122F81010401EF7D26F +:100AB000BDE8FF9F2DE9F0470546002016F0A9FB91 +:100AC000022016F0A6FB032016F0A3FB404F0020E7 +:100AD0003870384815F04CFFE8054FF0010403D595 +:100AE000FFF771FD3B480470354EDFF8EC80DFF80E +:100AF000EC90306890F86010890712D5290718D556 +:100B0000A90710D53C7090F8F001000602D5FFF758 +:100B100035FE01E0FFF714FF88F8004089F8004037 +:100B200001E0280705D5387818B9FFF7D3FC88F815 +:100B30000040DFF88080A80715D5387878BB30688A +:100B400090F8F001000603D50020FFF7B4FD07E0A0 +:100B5000184815F00DFF88F804401C48FFF779FC91 +:100B600089F800401BE0680719D5306890F8F0015B +:100B7000000603D50120FFF79EFD10E00D4815F09B +:100B8000F7FE306890F87000000702D588F804403E +:100B900002E0042188F804100C48FFF75AFC0320F7 +:100BA00016F052FB022016F04FFBBDE8F047002084 +:100BB00016F04ABBA8081000006F01202A6F012020 +:100BC0000407100040071000706410001056012048 +:100BD00000041000380710004507100044071000FB +:100BE00010B501464022F84818F028FB0121BDE865 +:100BF0001040002016F06DBA38B50446F348F24DA7 +:100C00002060204615F0D9FE00226B4601211046D7 +:100C100016F0A8FA0121002016F087FA287800289B +:100C200002D011F0E0FBECE738BD2DE9FF410024D4 +:100C3000DDE90A760821684617F04EF805460821D6 +:100C400002A817F049F8024600206FF07E0E14E06B +:100C5000002100FB02F30DE007EB010C13F90CC0BF +:100C6000B444F44501DA012403E0BCF17F0F00DD58 +:100C70000224491C9142EFDB401CA842E8DB2046DD +:100C800004B0BDE8F0812DE9FF410AAC082194E8E9 +:100C9000C0010024684617F01FF80546082102A885 +:100CA00017F01AF80146002008E03256D21901D593 +:100CB000012402E0FF2A00DD0224401CA842F4DBEC +:100CC00000200AE02A18B25612EB080201D50124CE +:100CD00002E0FF2A00DD0224401C8842F2DB2046AD +:100CE000CEE72DE9F04F87B04FF0010B15F0D6FE9F +:100CF00004460D4615F0D4FEDFF8D48206460F46B2 +:100D0000D8F8000090F8E70010F0600F05D02046FA +:100D1000294612F033FD04460D46AD48016891F8AE +:100D2000310091F8301000FB01F8012104A80FF008 +:100D3000DBFDDFF8A0920020DFF89CA2D9F80010BC +:100D4000049B324691F91B100390CDF800A0CDE929 +:100D500001313B462046294612F09AFD01200390BE +:100D60000021049BCDF800A0CDE9013132463B467D +:100D70002046294612F08CFD9348403015F0F8FDCE +:100D800091490520403108710846FFF735FF8E482C +:100D90000221D0F808A005A80FF0A6FD8C48424615 +:100DA0000168B1F9C2010190B1F9C4110091084480 +:100DB000401002905046059913F0EFFB8246022145 +:100DC00005A80FF0F4FD01984FF00008824502DC01 +:100DD00000998A450ADA7E4802990068AAEB010167 +:100DE000B0F8C60191FBF0F04FFA80F80499CDE914 +:100DF000001832463B4620462946FFF716FF0128D9 +:100E00001DD0022824D0D9F800100120724A81F8A0 +:100E10001B800390049B8DE80C0132463B46204624 +:100E2000294612F035FDD9F80000A521817601216F +:100E300004A80FF0BCFD07B05846BDE8F08FD9F804 +:100E400000104FF0000B81F81BB00121B02007E02B +:100E5000D9F800104FF0000BB12081F81BB0012130 +:100E600011F0B2FADFE72DE9F04FDFF8648189B0C5 +:100E70004FF0010BD8F8000090F831A090F8300046 +:100E8000079015F00BFE04460D4615F009FE0646C8 +:100E9000D8F800000F4690F8E70010F0600F05D07A +:100EA0002046294612F06AFC04460D46012104A89A +:100EB0000FF01AFDDFF81C914FF00008049BD9F8E1 +:100EC0000000294690F91D20444805900090CDF877 +:100ED0000C80CDE9013232463B46204612F0D8FC68 +:100EE000DDE904030121CDE90030CDE9028132467C +:100EF0003B462046294612F0CBFC3348403015F0E3 +:100F000037FD31490620403108710846FFF774FE6D +:100F10002D480221D0F8088006A80FF0E5FC2C48E7 +:100F20000068B0F9C811B0F9CA0108444010009037 +:100F3000079806990AFB00F2404613F02EFB824602 +:100F4000022106A80FF033FD21484FF00008006889 +:100F5000B0F9C821524503DBB0F9CA21524508DD7A +:100F6000009AB0F8CC01AAEB020191FBF0F04FFA25 +:100F700080F80499CDE9001832463B4620462946C0 +:100F8000FFF753FE4FF48071012829D002282FD09B +:100F9000D9F80010012081F81D80DDE90423CDE996 +:100FA0000032CDE9028032463B462046294612F007 +:100FB0006FFCD9F80000A5210177012104A80FF0EA +:100FC000F6FC584609B038E7B8081000910B00004D +:100FD0000407100008071000EC6F012014750120B1 +:100FE000D9F800204FF0000BB02082F81DB006E0C9 +:100FF000D9F800204FF0000BB12082F81DB011F09D +:10100000E3F9D6E72DE9F04F91B0DFF8B4A3012062 +:101010000F90DAF8000090F831100E9190F830003F +:101020000D9015F03BFD8046894615F039FD0446CC +:101030000D46012106A80FF057FCDAF8000002ABBC +:10104000002690F8340100F00101DE48006890F9B4 +:10105000202090F91F00059183E84500DA480699A1 +:101060000C90CDE9000122462B464046494612F03D +:1010700060FCDAF800000121224690F83401029663 +:1010800000F00100CDE9041006990C98CDE90001AB +:1010900003962B464046494612F04BFCCB4815F0D0 +:1010A00067FCCA49032088710846FFF7A5FDC748B9 +:1010B00002214038D0E90676DAF80000B0F9CEA176 +:1010C000B0F9D0B107A80FF00FFC0AEB0B004010ED +:1010D000059038460E9A079913F05FFA002750459D +:1010E00001DC584508DA0599091AB5480068B0F8D6 +:1010F000D20191FBF0F047B230460D9A079913F0F8 +:101100004CFA0026504501DC584508DA0599091AC1 +:10111000AB480068B0F8D40191FBF0F046B2022170 +:1011200007A80FF044FC0698CDE9000722462B469D +:10113000029640464946FFF7A6FD012826D0022820 +:101140002ED0A0480121224600682B46C77780F8A0 +:1011500020609B48006890F83401CDE9027600F0E9 +:101160000100CDE9041006990C98CDE90001404634 +:10117000494612F0DEFB9348A521006881770121E2 +:1011800006A80FF014FC0F9811B056E68D49002008 +:101190000F900968C87781F820001021B22008E07C +:1011A000884900200F900968C87781F82000102135 +:1011B000B32011F009F9DEE72DE9F04F8DB04FF0C3 +:1011C000010915F06BFC06460F4615F069FCDFF8C7 +:1011D000F0810121D8F8000090F831000A9006A8AB +:1011E0000FF082FBD8F80000764C4FF0000A90F820 +:1011F000E00902AB00F0010120685546DFF8C8B1F4 +:1012000090F9232090F92200059183E825000699A2 +:101210000BF1980BCDE900B15246534630463946A2 +:1012200012F087FBD8F800000121002290F8E009B5 +:10123000029500F00100CDE9041006990395CDE96F +:1012400000B113463046394612F073FB5F4815F083 +:101250008FFB5E49032008720846FFF7CDFC5B4810 +:1012600002214038856A09A80FF03EFBD8F800003B +:10127000B0F9D611B0F9D801084400EBD070401095 +:101280000190DDE90912284613F087F9D8F800101B +:101290000025AB46B1F9D621824203DBB1F9D82152 +:1012A000824206DD019AB1F8DA11101A90FBF1F0D2 +:1012B00045B2022109A80FF07AFB069900228DE8B9 +:1012C0002208134630463946FFF7DDFC012826D0B8 +:1012D00002282ED0216801223B4801F8225F81F8C4 +:1012E00001A0D8F8001091F83411029501F0010125 +:1012F0000591CDE903A206990022CDE9000113462C +:101300003046394612F015FB2168A52081F82100EE +:10131000012106A80FF04BFB48460DB08DE5216872 +:101320004FF0000901F822AF81F801A04021B2205E +:1013300008E021684FF00009B32001F822AF81F8DE +:1013400001A0402111F040F8DEE770B50546012408 +:10135000002015F05EFF022015F05BFF184E30688C +:1013600090F8C0012840C00703D0FFF7BAFC00F096 +:101370000104306890F8C001800704D5A80702D5A1 +:10138000FFF771FD0440306890F8C001400704D5B4 +:10139000680702D5FFF736FE0440306890F8C001B8 +:1013A000000704D5280702D5FFF706FF04400220F6 +:1013B00015F04AFF002015F047FF204670BD0000E1 +:1013C0000407100008071000DC7A0120F80810005C +:1013D00070B5764C4FF6FF714FF43E752068418230 +:1013E000294616F0B3FC00211F200EF131FC2A46DD +:1013F0002168BDE870401F236D4816F0CEBC6B48D5 +:1014000010B500686B4C417D206841744FF48C61CD +:1014100016F09CFC00211A200EF11AFC00211B2062 +:101420000EF116FC1A234FF480626348216816F00F +:10143000B4FC21681B23BDE8104060225F4801F521 +:10144000805116F0AABC2DE9F0415D4D041D0E46F9 +:101450002146284616F07AFC30685A4900EB84038E +:101460008B4201D21C2312E0574A934212D2884287 +:101470000CD28846091A8F081C233A46294616F0D2 +:101480008CFCE21B05EB87011D2311E01D23224686 +:1014900029460EE0904214D2111A8F0890461D235F +:1014A0003A46294616F079FCE21B05EB87011E231C +:1014B000404616F072FC306800EB84003060BDE8F6 +:1014C000F0811E23E3E7F8B53D4C4048009010340E +:1014D000022015F09EFE00211C200EF1B9FB002118 +:1014E0001D200EF1B5FB00211E200EF1B1FB1021D5 +:1014F000204617F0DDFE00202080A07001202B4D3B +:10150000E0704FF6FF71A1802868028AE280437D77 +:101510002F482372E688A0F8F86EA0F8FA1E04227D +:1015200080F8FC3E69461046FFF78DFF012300223C +:101530002146102012F01FFD6946FFF784FF0123AA +:1015400000222146112012F016FD6946FFF77BFFAD +:10155000286890F85012C90703D190F88002C0079C +:1015600008D0012300222146122012F004FD694612 +:10157000FFF769FF012300222146132012F0FBFC34 +:101580006946FFF760FF286890F85002C00708D04E +:10159000012300222146182012F0EDFC6946FFF7D6 +:1015A00052FF022015F050FEF8BD000004071000A5 +:1015B000F0EF010008071000F09F0100F0AF0100FC +:1015C00070641000F0CF0100F0DF0100F0BF0100F7 +:1015D000EC6F01200B4801785A2911D18188B1F5AF +:1015E0007C7F0DD8418800290AD106494078103106 +:1015F000022805D0A0F17002072A01D811F0CAB85C +:10160000704700000000012010B501464022FE484E +:1016100017F014FE0121BDE81040002015F059BD5F +:101620002DE9F041F94CA0F16006092ED4E912052C +:10163000D4E9142316D2DFE806F0051626374658FB +:101640006778870002462B46084600F09DF902465F +:101650000120002117F076FDD4E90223104319433D +:10166000C4E9020175E0084600F08EF90123024644 +:101670000021184617F066FDD4E90A2310431943E8 +:10168000C4E90A0165E002462B46084600F07CF9F1 +:1016900002460120002117F055FDD4E9062310432E +:1016A0001943C4E9060154E0084600F06DF902460A +:1016B0000120002117F046FDD4E90E231043194301 +:1016C000C4E90E0145E002462B46084600F05CF9ED +:1016D000012302460021184617F034FDD4E9042303 +:1016E00010431943C4E9040133E0084600F04CF903 +:1016F00002460120002117F025FDD4E90C231043F8 +:101700001943C4E90C0124E002462B46084600F0C8 +:101710003BF902460120002117F014FDD4E908230B +:1017200010431943C4E9080113E0084600F02CF9FE +:1017300002460120002117F005FDD4E910231043D3 +:101740001943C4E9100104E001208840616808439E +:1017500060602068401C2060BDE8F0812DE9F04108 +:10176000174604460D46002609E0E00703D031463F +:10177000384610F029FE761C6D084FEA340454EA0E +:101780000500F2D1E8E72DE9F041A04CD4E90223AD +:10179000D4E90656104619462A433343D4E90A567B +:1017A000D4E90EC745EA0C053E43D4E9087C9743CB +:1017B0002CEA030CC4E9087CD4E91023AA43B34300 +:1017C000C4E910232268002AC6D06022FFF7C6FFB2 +:1017D000D4E90A016122FFF7C1FFD4E906016222C0 +:1017E000FFF7BCFFD4E90E016322FFF7B7FFD4E98E +:1017F00004016422FFF7B2FFD4E90C016522FFF770 +:10180000ADFFD4E908016622FFF7A8FFD4E9100173 +:101810006722FFF7A3FF6068BDE8F041682200215E +:101820009CE799E72DE9F14F4FF0000915F036F9E3 +:101830000646884615F034F9744A04460D46C2E956 +:101840001401C2E912684FF01D0A4FF0260B15F083 +:101850003CFF00273A460120002117F073FC30407E +:1018600001EA0801084322D0F8B2002115F035FF43 +:10187000410705D50099C90602D54946622010E006 +:10188000C10705D00099490702D54946602008E004 +:10189000009911F0C00F06D010F00A0F03D049468E +:1018A0006420FFF7BDFE09F1010000F0FF097F1C75 +:1018B0005745CFDB15F009FF00273E463246012091 +:1018C000002117F03FFC20402940084320D0F0B20F +:1018D000012115F002FF410705D50099890602D5BF +:1018E0003946632010E0C10705D00099090702D5E9 +:1018F0003946612008E0009911F4C07F06D010F04D +:101900000A0F03D039466520FFF78AFE7F1CFFB21D +:10191000761C5E45D2DDBDE8F84F15F0D6BE10B599 +:101920000446002015F075FC3849002014F00C0F17 +:10193000C1E90800C1E90200C1E90400C1E90600EB +:10194000C1E91000C1E90A00C1E90C00C1E90E00BB +:101950004860086009D1E00607D4A00605D46006F7 +:1019600003D4E00501D4200602D52046FFF75AFF34 +:10197000A00702D0204600F022F8FFF704FFBDE8E0 +:101980001040002015F060BC2DE9F04116461F46BE +:1019900080464FF0FF35002422460120002117F039 +:1019A000D1FB30403940084304D06D1C454501D17E +:1019B0002046D1E6641C402CEED30020CCE62DE975 +:1019C000FF410446012000F038F8804615F066F823 +:1019D000CDE9000115F064F8CDE90201082168465F +:1019E00016F07AF90746082102A816F075F905469F +:1019F000074EE00707D0306842462946B0F8DE308F +:101A0000384600F04AF805E0080910000804100004 +:101A100004071000A00707D5306842462946B0F8F1 +:101A2000DE30384600F089F86A48016841F002016A +:101A300001600FF002FCBDE8FF8130B585B00446BF +:101A4000684614F095FF64480090022C15D00720DA +:101A50008DF80400614C684614F0AFFF002204AB1F +:101A60000121104615F07EFB0121002015F05DFBE1 +:101A7000207830B110F0B7FCEDE703208DF80900B5 +:101A8000E8E715F00BF8564DC5E9120115F008F816 +:101A9000C5E91401A06805B030BD2DE9FF5F9B4684 +:101AA00092460F46002544E000984FF000094C464E +:101AB000A0F101083AE000BF04FB075081B2601CAE +:101AC00000FB075080B23AF811203AF81000101AC3 +:101AD00000B2584502DDB9F1000F0AD0CBF1000188 +:101AE000884213DAB9F1000F06D04FF00009214601 +:101AF00018E04FF0010914E0002604E031466620AA +:101B0000FFF78EFD761CA642F8D90EE0B9F1000F62 +:101B10000BD021466620FFF783FD0098801E84428B +:101B200003D1611C6620FFF77BFD641C4445C3D3D1 +:101B30006D1CBD42B8D3BDE8FF9F2DE9FF5F9B46FA +:101B400092460D46002641E04FF000094C46A5F1B3 +:101B5000010838E006FB0540611C06FB051180B258 +:101B600089B23AF810203AF81100101A00B258451C +:101B700002DDB9F1000F0AD0CBF10001884213DA7F +:101B8000B9F1000F06D04FF00009214617E04FF0E1 +:101B9000010913E0002704E039466720FFF740FD04 +:101BA0007F1CA742F8D90DE0B9F1000F0AD02146F9 +:101BB0006720FFF735FDA81E844203D1611C672012 +:101BC000FFF72EFD641C4445C4D3761C0098864262 +:101BD000BAD3B0E72C071000B915000008091000AF +:101BE00008041000144908604FF40051002015F05B +:101BF00070BA38B5002015F00CFBAFF2170017F0E3 +:101C0000ADF900224FF400546B462146104615F002 +:101C1000A9FA2146002015F088FA002015F014FBDF +:101C20000648A522016804480A74006820F07F4233 +:101C30004A6117F0B7F938BD6004100008071000BA +:101C4000020004D0012A04D0022805D002E00120BD +:101C500000E0042014F015BE0020704710B50146C6 +:101C60004022FE4817F0EAFA0121BDE810400020AA +:101C700015F02FBA30B585B00446684614F078FEEA +:101C8000F74800900CB3012C21D0022C21D0032C5A +:101C900019D108208DF80400F04D0324684614F093 +:101CA0008CFE002204AB0121104615F05BFA0121E5 +:101CB000002015F03AFA2878002804D010F093FBA1 +:101CC000641E002CEADC05B030BD0520E2E70620EA +:101CD000E0E702208DF80900DEE72DE9F14F88B03A +:101CE00014F0DCFE8346029114F0DAFE8146DD4CEE +:101CF00008988A460028206807D0B0F87A1108981A +:101D0000FFF79EFF0490D84812E090F8E70010F02B +:101D1000600F05D05846029911F030FD83460291BC +:101D20002068B0F872110898FFF78AFF0490CF4836 +:101D30000390402007900690C848B821B83817F0A3 +:101D4000D9FA002000900898FFF794FFC3480027B5 +:101D50003E468068059001203D4601902A460120BC +:101D6000002117F0EFF9029A00EA0B001140084336 +:101D700041D0002422460120002117F0E3F9024659 +:101D80000B4600EA090001EA0A01084320D0B348E3 +:101D9000B83800EBC6018E4603C900EA020C01EA1E +:101DA00003085CEA080C12D1DDF814C03CF9178076 +:101DB000DDF810C0E04504DC10431943CEE9000112 +:101DC00005E022463146009B039815F0D6FB7F1CA8 +:101DD0000698641C8442CDDBA048B83800EBC601ED +:101DE000D1E9000280EA090082EA0A02104301D028 +:101DF00000200190761C07986D1C8542AEDB01988F +:101E0000012804D00098401C00907F289BDD019899 +:101E100009B0BDE8F08F2DE9F14F98B014F03EFE07 +:101E2000CDE90C0114F03CFECDE9100118988D4C61 +:101E300000285CD02068B0F87A111898FFF700FFEE +:101E40000F9089480690402082460E9008210CA8E9 +:101E500015F042FF0446082110A815F03DFF444349 +:101E60008348019000F5E6602146029017F020FAC1 +:101E70006100019817F01CFA7848B821B83817F0BB +:101E800039FA4FF000091898FFF7F4FE734800275D +:101E90003C4680680A90C9F100004FF0010B3E46B5 +:101EA000139032460120002117F04CF9DDE90C2394 +:101EB0001040194008436ED000252A460120002119 +:101EC00017F040F9DDE9108C02460B4600EA0800E5 +:101ED00001EA0C01084373D06048B83800EBC70C26 +:101EE000DCE900011040194008430FD093E0DDE920 +:101EF0000C0111F043FCCDE90C012068B0F872111F +:101F00001898FFF79DFE0F9058489BE7B9F1000F16 +:101F10000ADA0A9830F914100F98814201DB002187 +:101F200000E00121029801550A980F9930F9140038 +:101F3000884231DD0299095D11B1012909D06AE0B9 +:101F4000B9F17F0F67DA019909F1010321F8140053 +:101F500051E0DCE9001011431843CCE9001001986E +:101F600030F914100F98091A0A9830F914200F98B4 +:101F7000A2EB000000D54942002800DA404281422D +:101F800005DC139B2A4639465B1C069836E001980F +:101F900020F814203FE052E037DA0299095D012968 +:101FA00001D071B137E0139911F17F0F33DD019941 +:101FB0002A4621F81400139B39465B1E06981DE043 +:101FC0002AE0DCE9001011431843CCE90010019825 +:101FD0000F9A30F914100F98081A0A9931F9141051 +:101FE000A1EB020200D54042002A00DA52429042A0 +:101FF00007DCA9F101032A463946069815F0BDFA17 +:1020000009E0019820F8141005E0DCE90010114304 +:102010001843CCE90010641C6D1C5545FFF64DAF0C +:102020000E48B83800EBC701D1E90001DDE9102303 +:1020300050405940084301D04FF0000B7F1C0E98D0 +:10204000761C8642FFF62DAFBBF1010F05D009F1DA +:102050000109B9F17F0F7FF716AF0BE0000A1000FE +:102060000D1C00000407100014750120EC6F012006 +:1020700070641000584619B0CBE62DE9F04F0546C4 +:1020800085B0002015F0C5F8022015F0C2F814F054 +:1020900007FDCDE90201F84804904027082102A875 +:1020A00015F01AFE0446012D71D1DDE90201CDE9DA +:1020B000000101220023049815F06EFADFF8BC83BA +:1020C00000216FF07E0508EB440A680C05E000BFB4 +:1020D00028F811000AF80150491CA142F8DBDFF88A +:1020E000A0B30320FFF7C6FD0024DBF808902646C6 +:1020F00032460120002117F025F8DDE902231040C7 +:10210000194008431DD039F9141038F9140000297A +:1021100000DA4942002800DA404281420ADA3246B7 +:102120000021049815F01EFA0AF8040039F814107A +:1021300028F814102B4632460021049815F01DFA99 +:10214000641C761CBE42D3DB6D1C7F2DC9DD0025CF +:102150002C4622460120002116F0F4FFDDE902237F +:1021600010401940084307D01AF9053022460021D3 +:10217000049815F002FA6D1C641CBC42E9DBC148EE +:1021800026220499006800F5865017F012F8022004 +:1021900015F05AF8002015F057F805B039E62DE98A +:1021A000F04F87B0002015F034F8022015F031F818 +:1021B0004FF0000B14F074FCCDE90401AE4803901D +:1021C000082104A815F088FD06460020DFF8AC823F +:1021D000CDE9000008EB460505EB06090320FFF7F3 +:1021E00049FDDFF89CA200242746DAF80800029097 +:1021F0001AE03A460120002116F0A4FFDDE904238D +:102200001040194008430ED03A460021039815F0BB +:10221000A9F92855029830F8141028F81410002055 +:1022200009F80400641C7F1CB442E2DB00273C4632 +:1022300015E022460120002116F084FFDDE9042389 +:1022400010401940084309D0EB577F2B05DA22468E +:1022500000215B1C039815F090F97F1C641CB742A9 +:10226000E7DB0320FFF706FD00200124DAF8083041 +:1022700014E000BF33F9102038F91010002A00DAFA +:102280005242002900DA49428A4206DA29567F2959 +:1022900003DA491C295409F80040401CB042E9DB2C +:1022A00000273C4616E022460120002116F04AFF96 +:1022B000DDE904231040194008430AD0EB5713F11D +:1022C0007F0F05DD224600215B1E039815F055F9AE +:1022D0007F1C641CB742E6DB0320FFF7CBFC684899 +:1022E0008368002019E000BF19F80010A1B933F984 +:1022F000101038F91020002900DA4942002A00DACB +:102300005242914208DA295611F17F0F04DD491E2D +:102310002954022209F80020401CB042E4DB0024CA +:10232000274627E03A460120002116F00BFFDDE9A1 +:1023300004238246029110401940084319D02B57BC +:102340003A460021039815F018F919F8040078B9F5 +:10235000DDE9002302994AEA02001943CDE90001B0 +:1023600038F91400FE30B0F5FE7F01D94FF0010BB3 +:10237000641C7F1CB442D5DB0821684615F0ACFC18 +:10238000B04208DBBBF1000F03D00021B42010F0F5 +:102390001BF807B03DE5002036E00320FFF76AFC9C +:1023A0003748002427468068029023E03A460120FF +:1023B000002116F0C7FEDDE9043C02468E461840B7 +:1023C00001EA0C01084314D0DDE9000302EA000C25 +:1023D0000EEA03015CEA010C0AD119F90410012983 +:1023E00035D002296DD002434EEA0301CDE9002128 +:1023F000641C7F1CB442D9DB0821684615F06CFCD4 +:10240000B04208DA0AF1010082461F48006890F8DD +:10241000E2115145C1DC1B4826220399006800F5F2 +:10242000865016F0C6FE0821684615F055FCB042ED +:1024300002DBBBF1000F03D00021B4200FF0C4FF7A +:10244000022014F001FF002014F0FEFEA1E7029824 +:1024500038F9141030F91400002801DB034600E0BD +:102460004342002900DA49428B420FDC295D7F2973 +:102470000CD028F8140050E0847F01207064100014 +:10248000000A10000807100004071000002109F8D6 +:102490000410DDE90001024302984EEA0103CDE990 +:1024A000002330F9141038F91400002900DA4942E9 +:1024B000002800DA4042814232DD285D401E285566 +:1024C0002EE0029830F9141038F91400002901DBCD +:1024D0000B4600E04B42002800DA4042834205DC14 +:1024E00028577F3002D028F81410E6E7002009F8BA +:1024F0000400DDE900130A434EEA0300CDE90020A1 +:10250000029830F9141038F91400002900DA494211 +:10251000002800DA4042814202DD285D401CCEE7FF +:102520002B573A460021039815F027F860E72DE96C +:10253000F04106460124002014F06BFE022014F046 +:1025400068FE4A4DF0074FF000074FF0A50808D08D +:1025500000F01BF810F0010403D02868C77680F85B +:102560001A80B00708D500F056F82040040003D0C8 +:102570002868477780F81C80002014F065FE022050 +:1025800014F062FE2046BDE8F0812DE9FC470126EB +:1025900014F084FA04460D4614F082FADFF8D09065 +:1025A00007468846D9F8000090F8E70010F0600F61 +:1025B00005D02046294611F0E1F804460D46D9F829 +:1025C000000090F87001C0071FD0CDE900782246C6 +:1025D0002B46284814F0E0FFD9F8000090F870115D +:1025E000C90712D090F8E700C0F3411002284FF05D +:1025F000000002D3FFF70FFC01E0FFF76EFB0600BF +:1026000003D1012174200FF0DFFE0020FFF732FB21 +:102610003046BDE8FC872DE9FC41012614F03EFA66 +:1026200004460D4614F03CFA114F3A6892F87821AE +:10263000D20715D0CDE9000122462B460E4814F0F2 +:10264000ABFF386890F87801C00709D00120FFF788 +:1026500044FB060004D14FF4807174200FF0B4FEE7 +:102660000120FFF707FB3046BDE8FC81080710009A +:1026700004071000EC6F01201475012010B5FFF75E +:10268000B8FA0120FFF7F9FC012000F075F953209A +:10269000FFF74DFF00F001044FF4D67001F058F938 +:1026A000204205D0FEF70FFFBDE81040FEF7A7BEA1 +:1026B00010BD10B5FFF79DFA0120FFF7DEFC0120E9 +:1026C00000F05AF940F2FF10FEF73FFE002803D059 +:1026D000BDE81040FEF793BE10BD000010B50146E6 +:1026E0004022FD4816F0AAFD0121BDE8104000205F +:1026F00014F0EFBC30B585B0684614F039F9F748EE +:1027000002230078B0B10321012816D0032817D086 +:10271000022818D00422052818D0042819D0072828 +:102720001AD006281BD008281CD009281DD00A283A +:102730001ED01FE08DF806301CE08DF8061019E061 +:102740008DF8081016E08DF8083013E08DF80A2097 +:1027500010E08DF80A100DE08DF80B100AE08DF8EE +:102760000B3007E08DF8062004E08DF8082001E02A +:102770008DF80B20DA48D84D03240090684614F0F9 +:102780001CF9002204AB0121104614F0EBFC0121DE +:10279000002014F0CAFC2878002804D00FF023FE93 +:1027A000641E002CEADC05B030BD2DE9F04FCB4EA5 +:1027B000044687B008208846307014F06FF9CDE9E0 +:1027C0000001402005903620C64D03907CB3012CBB +:1027D0003AD0022C4AD00A20042C55D0052C7DD1A9 +:1027E000307014F065F9CDE90001BB4C286841F266 +:1027F0009A01383400EB010BDFF8ECA2262003909D +:102800000821684615F068FA0746B8F1010F65D14E +:102810003A466946504614F0FFFEDFF8D0926FF05A +:102820007E0109EB4700029000204A0C43E0FFE7DD +:10283000DFF8B4A2A84C296841F2E600AAF1880AA0 +:10284000183401EB000BDBE714F02AF9CDE90001A5 +:10285000A14C286841F21C11DFF88CA21C3400EB5B +:10286000010B2620AAF1680A0390C9E709203070FD +:10287000DFF874A2984C286841F24211AAF1400A8C +:10288000283400EB010BBBE7307014F00FF9CDE9F1 +:102890000001DFF854A2904C286841F26401AAF1CB +:1028A000200A343400EB010BAAE700BF29F81020FE +:1028B000029B1954401CB842F8DB8846FFF71AFF08 +:1028C000206800252E46049032460120002116F093 +:1028D00039FCDDE900231040194000E049E00843DD +:1028E0001DD0049830F9151039F91500002900DAC7 +:1028F0004942002800DA404281420ADA3146504615 +:1029000014F078FE02994855049830F8151029F80B +:10291000151042463146504614F073FE6D1CBD4200 +:1029200003D00598761C8642CEDB08F10108B8F189 +:102930007F0FC3DD00252C4622460120002116F022 +:1029400001FCDDE9002310401940084306D002983D +:1029500021464257504614F054FE6D1CBD4203D030 +:102960000598641C8442E7DB51465846039A16F0EA +:1029700020FC07B0BDE8F08F10B50446002014F02D +:1029800048FC022014F045FC21460020FFF70DFF13 +:1029900021460120FFF709FF21460220FFF705FF2E +:1029A00021460420FFF701FF21460520FFF7FDFE29 +:1029B000022014F049FCBDE81040002014F044BC93 +:1029C0002DE9F04F454E04468DB00820307014F0CC +:1029D00065F8CDE90601DFF8188136200590D8F8B2 +:1029E000000010213F4D90F8E3910991ACB3012C08 +:1029F0003FD0022C4ED00A21042C5CD0052C6AD189 +:102A0000317014F055F8CDE9060137480090286878 +:102A100041F29A010844049026200590D8F800005D +:102A20002D4F383790F8E5910820099000200A9042 +:102A3000082106A815F050F9DFF8B0B006460BEBF8 +:102A40004605A81908900020CDE90200FFF752FEC4 +:102A500000242046D7F800A066E0FFE722481E4F7A +:102A600088380090286841F2E6010844183704903D +:102A7000DCE714F015F8CDE906011B48164F68385D +:102A80000090286841F21C1108441C37049026204D +:102A90000590CBE709213170134941F242124039C8 +:102AA000009129680C4F11440491283790F8E49163 +:102AB00040200990BAE731700B4941F26402203995 +:102AC00000912968044F11440491343790F8E5913E +:102AD00008200990AAE722E1400A100068041000CB +:102AE0008D2600000807100034800120706410005B +:102AF0000407100002460120002116F023FBDDE947 +:102B000006231040194008430CD04146009814F0A9 +:102B100071FD28553AF814102BF81410089800216C +:102B20000155641C08F101008046B442E2DB002438 +:102B3000204615E002460120002116F003FBDDE9E6 +:102B4000062310401940084308D02A577F2A04DA88 +:102B50004146521C009814F054FD641C08F1010019 +:102B60008046B442E6DBFFF7C5FD002001243B6848 +:102B700014E000BF33F910203BF91010002A00DAEE +:102B80005242002900DA49428A4206DA29567F2950 +:102B900003DA491C295408990C54401CB042E9DB63 +:102BA0000024A0466FF07E0A15E042460120002175 +:102BB00016F0C8FADDE9062310401940084308D092 +:102BC0002A57524504DD4146521E009814F019FD63 +:102BD000641C08F10108B442E7DBFFF78BFD00201D +:102BE0003B6817E00899095C99B933F910203BF963 +:102BF0001010002A00DA5242002900DA49428A42C3 +:102C000007DA2956514504DD491E29540899022244 +:102C10000A54401CB042E5DB0024204627E002466F +:102C20000120002116F08EFA0191DDE9062382468B +:102C300010401940084318D02A574146009814F014 +:102C4000E0FC0898005D78B9DDE90121039B4AEAC0 +:102C500001001A43CDE902023BF91400FE30B0F541 +:102C6000FE7F01D901200A90641C08F10100804612 +:102C7000B442D4DB082102A815F02EF8B04247DA9E +:102C8000002037E0FFF736FD386800240190204629 +:102C900025E002460120002116F054FADDE9068CF9 +:102CA00002460B4600EA080001EA0C01084314D072 +:102CB000DDE9020C02EA000103EA0C0851EA08010E +:102CC0000AD10899095701292BD0022959D002436A +:102CD00043EA0C03CDE90223641C0AF10100824699 +:102CE000B442D6DB082102A814F0F6FFB04204DAA1 +:102CF0000B98401C0B904845C4DBDDE904020099A9 +:102D000016F057FA082102A814F0E6FFB04202DBE1 +:102D10000A98002803D0B52009990FF055FB0DB093 +:102D200028E601983BF9141030F91400002801DB63 +:102D3000844601E0C0F1000C002900DA49428C45CC +:102D400005DC295D7F2902D02BF8140045E00898A6 +:102D500000210155DDE90201024301980B43CDE951 +:102D6000022330F914003BF91410002800DA404225 +:102D7000002900DA4942884232DD285D401E28558C +:102D80002EE0019830F914103BF91400002901DB02 +:102D90008C4601E0C1F1000C002800DA4042844575 +:102DA00005DC28577F3002D02BF81410E5E708988F +:102DB00000210155DDE90201024301980B43CDE9F1 +:102DC000022330F914003BF91410002800DA4042C5 +:102DD000002900DA4942884202DD285D401CCEE726 +:102DE0002A575146009814F00CFC75E710B50020E6 +:102DF00014F00FFA022014F00CFA0020FFF7E0FDA7 +:102E00000120FFF7DDFD0220FFF7DAFD022014F0BC +:102E10001BFABDE81040002014F016BA2DE9F04767 +:102E2000FF4800252C46D0E91478D0F834902E467F +:102E3000824632460120002116F084F9384001EA2A +:102E40000801084304D019F80600A84200D9054635 +:102E5000761C402EEDD3DAE91678DAF838900026A1 +:102E600032460120002116F06DF9384001EA0801D0 +:102E7000084304D019F80600A04200D90446761C85 +:102E8000402EEDD3DAF8442050461570DAF8481099 +:102E90000C70DAF82C30DAF82470DAF830601B782D +:102EA0003F782B443B44DAF8287036783F78264444 +:102EB0003E44D0E9147C57EA0C070DD0D0E9167CCB +:102EC00057EA0C070AD0FF27B34213D2F31A2B4458 +:102ED000FF2B07D813700BE0147009E015700D700C +:102EE000BDE8F0871770826942F40072CAF81820B2 +:102EF0000C70F5E79E420DD29B1B2344FF2B01D89B +:102F00000B7005E00F70816941F40071CAF8181068 +:102F10001570E5E71570EBE72DE9F0411F460D460A +:102F2000002A1FDDBE4C77B1B4F90A60114611F0DA +:102F300096FBB042287812DAFF2807D2401C28708E +:102F40000020BDE8F081B4F90860EFE7A0691FB187 +:102F500040F00200A06105E040F40060FAE708B12B +:102F6000401E28700120ECE72DE9F0411E460D4679 +:102F7000002A1ADDAA4C66B1B4F90A70114611F0A4 +:102F80006EFBB84211DD287850B1102804D31038F8 +:102F900003E0B4F90870F1E7002028700020D0E7C2 +:102FA000A06926B140F00100A0610120C9E740F40A +:102FB0008060F9E72DE9F14F82B000259848029A28 +:102FC0002C46FF2102B3D0F82C9002264FF0180BAC +:102FD00089F80010D0F8308088F80010B0F90A7035 +:102FE000310200910169002900DC01258C4840690B +:102FF000002800DC0124FFF711FFFFF77BFB00989E +:103000000FF07DF985B121E0D0F824904FF40066EF +:103010004FF0180B89F80010D0F8288088F80010BD +:10302000B0F90870F110DCE7DFF8F4A13A46DAF8FD +:103030001C00DAF81010006800F0D7FC012805D158 +:10304000DAF8181031430125CAF818108CB9DFF8E6 +:10305000D0A13A46DAF82000DAF81410006800F03F +:10306000C4FC012805D1DAF8181031430124CAF84C +:1030700018100DB1002C4ED12F4626464FF0170ADE +:103080004FB96748029BC16902690F6849463846D3 +:10309000FFF76AFF07464EB96148029B016A426921 +:1030A0000E6841463046FFF75FFF0646FFF7B6FE63 +:1030B000FFF720FB00980FF022F907B116B9BAF11B +:1030C000010ADDD22F46564DABF101063FB9E86942 +:1030D000029B494600682A69FFF71EFF07463CB974 +:1030E000286A029B414600686A69FFF715FF04469B +:1030F000FFF794FEFFF7FEFA00980FF000F907B112 +:103100000CB9761EE2D2012F05D1012C03D1A8699A +:1031100020F40070A861BDE8FE8F2DE9F04F9A46BB +:10312000914600223E4B83461446B3F90C7010467C +:103130000123904615E000BF09EBE40504F0070CFD +:103140002E7803FA0CF535420AD03BF91250BD42F5 +:1031500003DC0AF80230012001E00AF80280521C68 +:10316000641C8A42E8DB05E42DE9FF5F00244FF090 +:1031700001089A4617462546DFF8A4904646DDF832 +:103180003CB051E00AEBE50005F00701007806FAD3 +:1031900001F2024247D01BF8040001283FD00098FA +:1031A000B9F90C1030F914208A421DDA2946019829 +:1031B00014F04DFAFF280EDA401CC2B24FF000089E +:1031C0002946019814F045FA009830F814100E982A +:1031D00020F8141023E00BF80460D9F8181041F01F +:1031E0000801C9F818101AE00E9830F914000028E8 +:1031F00013DD401AA2EB010100D54042002900DA9C +:103200004942884209DC2946019814F020FA401E00 +:10321000C2B22946019814F01CFA0BF8046001E0D0 +:1032200068041000641C6D1CBC42ABDB404604B05B +:10323000BDE8F09F2DE9FF5F00244FF001089A469A +:10324000174625464646DFF86C94DDF838B030E086 +:103250000AEBE50005F00702017806FA02F00842E1 +:1032600026D01BF80400012821D0009830F9141052 +:10327000B9F90C0081421ADD2946019814F0E7F9EA +:1032800000280CDD4FF00008042801DB001F00E0DF +:103290000020C2B22946019814F0DBF907E00BF8D0 +:1032A0000460D9F8181041F00401C9F81810641C22 +:1032B0006D1CBC42CCDB4046B9E72DE9F04F95B020 +:1032C0000024254620210CA816F014F8282102A875 +:1032D00016F010F8F7480169002900DC0124426962 +:1032E000002A00DC0125F34A81460646FF235032BE +:1032F000406B00F084FBEF4AFF2358327169B06BDA +:1033000000F07DFBFFF78AFDFFF7F4F94FF4806AC8 +:1033100050460EF0F4FF8CB1D9F81C00E54A4E4639 +:1033200000680CAB5032D9F81010FFF7F6FE0128F8 +:1033300004D1B069012440F00800B0618DB1D9F822 +:103340002000DC4A4E46006802AB5832D9F814100F +:10335000FFF7E3FE012804D1B069012540F0080021 +:10336000B0610CB1002D78D12646A84600276EB971 +:103370000CA80090D9F81C00CE4BD9F8102000689A +:103380005033D9F83410FFF755FF0646B8F1000F57 +:103390000DD102A80090D9F82010C64BD9F81420FE +:1033A00008685833D9F83810FFF744FF8046FFF714 +:1033B00035FDFFF79FF950460EF0A1FF16B1B8F1A9 +:1033C000000F02D17F1C602FD1DBDFF8ECB2D9F8FF +:1033D0001000264641000BF5E6684C46584615F0AD +:1033E00067FF60694100404615F062FF0027D14643 +:1033F000FFF780F948460EF082FF5EB90CA8CDE9D0 +:1034000000B0E069AB4B226900685033616BFFF795 +:10341000ABFE06465DB902A9CDE90081206AA54B45 +:10342000626900685833A16BFFF79EFE0546FFF7FF +:10343000F5FCFFF75FF948460EF061FF06B115B9DC +:103440007F1C602FD4DB012E07D1012D05D1A0698F +:10345000810502D520F40070A06115B083E62DE946 +:10346000FF5F4FF0010800259A4617462C46DFF80B +:1034700044924646DDF83CB03AE000BF0AEBE40077 +:1034800004F00702017806FA02F008422FD01BF878 +:10349000040058BB2146019814F0ACF80099B9F922 +:1034A0000E2031F915304946934212DD0E9A7F3ACB +:1034B000904208DD0E99421A2146019814F0A1F8B5 +:1034C0004FF0000812E0886940F04000C9F8180089 +:1034D0000CE00BF804600E99C1F17F01814205DD1B +:1034E0000E9942182146019814F08BF86D1C641C4B +:1034F000BD42C3DB40469AE62DE9F04F6D4C9FB0CC +:103500002169B9B3002083466069A0B300208246D8 +:10351000BBF1000F02D0BAF1000F5AD1674B04ADD6 +:103520000DCB85E80D00634A7F235032E06B00F03D +:1035300066FA604A7F2358326169206C00F05FFAB6 +:103540000026A14604A85C4650F826805546202156 +:1035500011A815F0CFFE282107A815F0CBFED9F849 +:103560001810002721F04001C9F81810FFF7C2F821 +:1035700034B114E000E001E00120C4E70120C6E717 +:1035800011A9CDE90081D9F81C104A4BD9F81020B7 +:1035900008685033D9F83C10FFF761FF044675B94D +:1035A00007A9CDE90081D9F82010424BD9F81420A1 +:1035B00008685833D9F84010FFF751FF0546FFF768 +:1035C0002DFC04B115B97F1C182FCFDB761C032E00 +:1035D000B8D31FB0C7E570B5364C00260546A661C6 +:1035E000012863D0022D63D0032D6AD00120207002 +:1035F000607968B12F4A002350322169606B00F076 +:10360000FEF92C4A002358326169A06B00F0F7F9EB +:10361000A07958B1274922695031E06B13F0FCFFC3 +:10362000244962695831206C13F0F6FFE07810B13C +:103630000020FFF7BFFC207960B1E07838B16178F5 +:10364000606A00F0CAF96178A06A00F0C6F901204A +:10365000FFF7B0FC607908B1FFF72FFE012D32D0E3 +:10366000022D32D0032D32D084F80060FFF742F8EB +:10367000A07958B1207938B1A178E06A00F0ADF9AD +:10368000A178206B00F0A9F9FFF736FFFFF732F8B9 +:10369000012D1FD0022D1FD0032D20D01021A06995 +:1036A00000F0C2F9A069E0B1002070BD03209EE7E0 +:1036B00005209CE76804100070641000BC950100B0 +:1036C000FFE7072093E7022002E0042000E0062045 +:1036D0002070CBE74021E2E74FF40071DFE70821DB +:1036E000DDE7012070BD70B5EA4D0C46022828D0F8 +:1036F00013F0D4F9C5E9140113F0D2F9C5E91601A4 +:10370000E4480821503014F0E7FA2861E148082124 +:10371000583014F0E1FA686104F190006862401CCE +:10372000A862401CE862401C28634B386863203064 +:10373000C5E90E044838286474309534C5E911048D +:1037400070BD13F0AFF9C5E9140113F0ADF9D5E779 +:1037500010B5D1490020FFF7C6FFCE48CF49C1615F +:10376000091D0162CE490B6893F8882112F001040B +:10377000C4704FF0000204D0436A1A70836A1A7052 +:1037800008E0446A93F8923123700B68846A93F8D6 +:10379000933123700B6893F88841C4F3400404719B +:1037A00014B1C36A1A7006E093F89421C36A1A70C0 +:1037B0000A6892F89521036B1A70096891F88821BC +:1037C000C2F380034371C2F3C0028271B1F88A214F +:1037D0000281B1F88C214281B1F88E218281B1F849 +:1037E0009021C28191F89621427091F897118170D1 +:1037F000BDE810400020EEE610B5AA490320FFF70F +:1038000072FFA649A3481C31C161091D0162A44988 +:103810000B6893F8D92A12F00104C4704FF000022B +:1038200004D0436A1A70836A1A7008E0446A93F8F5 +:10383000DA3A23700B68846A93F8DB3A23700B68DA +:1038400093F8D94AC4F34004047114B1C36A1A70DE +:1038500006E093F8DE2AC36A1A700A6892F8E52A2D +:10386000036B1A70096891F8D92AC2F38003437177 +:10387000C2F3C0028271B1F8DC2A0281B1F8DF2AFA +:103880004281B1F8E12A8281B1F8E32AC28191F83C +:10389000E62A427091F8E71A8170BDE810400320D3 +:1038A00099E67D4910B598310120FFF71CFF7B494F +:1038B00078481031C1610021C0E916110A46416102 +:1038C00077490B6893F8A04114F00104C47004D048 +:1038D000436A1A70836A1A7008E0446A93F8AA313E +:1038E00023700B68846A93F8AB3123700C6894F8EA +:1038F000A031C3F34003037113B1C36A1A7006E029 +:10390000C36A94F8AC211A700A6892F8AD21036B6F +:103910001A70096891F8A021C2F380034371C2F3C1 +:10392000C0028271B1F8A2210281B1F8A4214281C2 +:10393000B1F8A6218281B1F8A821C28191F8AE2107 +:10394000427091F8AF118170BDE81040012042E64D +:103950002DE9F04107460124002013F05AFC022013 +:1039600013F057FC504E78074FF000054FF0A508B4 +:103970000AD5FFF7EDFE10F0010405D03068C577D9 +:1039800080F8205080F81E8038070AD5FFF789FF9D +:103990002040040005D0306800F8225F457000F830 +:1039A000018C3F48006890F80E0BC0070CD0F8055A +:1039B0000AD5FFF721FF2040040005D0306800F849 +:1039C0002A5F457000F8018C022013F03DFC0020B6 +:1039D00013F03AFC2046BDE8F08102788A4201D912 +:1039E000511A00E000210170704710B5144610F024 +:1039F00036FEA04201DC012010BD002010BDF0B554 +:103A000000252C4601260CE002EBE40704F0070C2D +:103A10003F7806FA0CFE1EEA070F01D003556D1C15 +:103A2000641C8D42F0DBF0BD70B504460D46C00746 +:103A300002D083200EF0C8FCA00703D529468420BD +:103A40000EF0C2FC600703D5294685200EF0BCFCB1 +:103A5000200703D5294686200EF0B6FC600603D564 +:103A600029468B200EF0B0FC200603D529468C2079 +:103A70000EF0AAFCE00503D5294687200EF0A4FC31 +:103A8000A00505D52946BDE8704088200EF09CBCF5 +:103A900070BD000068041000DC7A0120580A100094 +:103AA00004071000EC7E012008071000DFF8849165 +:103AB00008B5614D0024DFF884A1C9F80040604ECC +:103AC0002C60DFF88081CAF80040DFF87CB13460F8 +:103AD000C8F80040CBF8004000226B465B49104616 +:103AE00013F040FB0098810713D5FCF787FC2F6883 +:103AF0002C60FCF781FC17F0530F02D03846FEF71C +:103B000016FD17F4D67F02D03846FFF721FF0221B9 +:103B10008BE0810504D5FEF76CF84FF4007184E06A +:103B2000410514D5FCF76AFC37683460FCF764FC87 +:103B3000F80701D0FDF74CFCB80701D5FDF7C3FC31 +:103B4000780701D5FDF75BFC4FF480616DE001065D +:103B50000CD5FCF753FCD8F80070C8F80040FCF70F +:103B60004BFC3846FDF7DBFE80215EE081020DD57F +:103B7000FCF744FCDAF80070CAF80040FCF73CFCA3 +:103B80003846FDF7E2FB4FF400114EE0C10404D5C6 +:103B9000FEF774FD4FF4805147E0010204D5FDF7B4 +:103BA00019FD4FF4000140E0010504D5FEF781FD49 +:103BB0004FF4006139E0410227D5FCF71FFCDBF828 +:103BC0000070CBF80040FCF717FCF80701D0FEF7B7 +:103BD00010F8B80705D50120FEF74FFA0120FEF7CF +:103BE000CBFE38070ED51A4F386890F8C101000691 +:103BF00001D5FEF7D4FA386890F8C101400601D526 +:103C0000FFF7F4F84FF480010FE0C0057FF564AFD3 +:103C1000FCF7F4FBD9F80070C9F80040FCF7ECFBA6 +:103C20003846FCF747FF4FF48071002013F07DFA0F +:103C300052E7000014071000180710001C071000BE +:103C4000200710002407100028071000839FF000B1 +:103C5000040710002C4810B501682C480268134670 +:103C600092EA010F4ED02A4ACC07126834D092F85B +:103C70002B43E40702D043F0010303608B072ED5EA +:103C800092F84033DB0703D0036843F0020303607C +:103C90000B0728D592F86033DB0703D0036843F0A5 +:103CA000080303604B0622D592F86033DB0703D08C +:103CB000036843F040030360CB051CD592F8932AB8 +:103CC000520703D5026842F48072026089050168D8 +:103CD00015D541F4007114E023F00103CDE703682A +:103CE00023F00203D3E7036823F00803D9E703684E +:103CF00023F04003DFE7026822F48072E5E721F455 +:103D00000071016010BD000034071000F0041000C5 +:103D1000040710002DE9F047DFF868929A4C00255F +:103D2000D9F8000090F8311084F8301090F8302065 +:103D3000964884F831205143037B84F8333000F1F6 +:103D400040032360837B0EB284F82D3080467700D9 +:103D50000FE02A463146D8F808000FF086FA0146EF +:103D6000226806FB05F002EB40003A4615F021FA06 +:103D70006D1C94F82D00A842EBDC8548854900783D +:103D800009780843400711D583486060D9F80010CE +:103D900091F8F11189074A0F94F83110921C4A43A7 +:103DA000D8F81010BDE8F04715F003BABDE8F08769 +:103DB0002DE9F041764F774C00263D682068054399 +:103DC000012013F026FA40216F4815F093FAE80716 +:103DD00006D0FFF79FFFE80601D500F083F8012623 +:103DE0006E480078400603D5E80601D50DF025FAA7 +:103DF000280702D500F0A5F8012669480168624845 +:103E0000C161056222684262604A2946654D526876 +:103E100082622A7880F82C20CA071CD00446C80683 +:103E200019D5584F386890F85002C00706D000F0F6 +:103E30006DFE18B9E06940F01000E061386890F854 +:103E40008002C0070CD000F061FE48B9E06940F084 +:103E50002000E06104E03878400601D50DF0EDF96E +:103E6000012013F0F1F9002E0CD02878052807D096 +:103E7000062805D00121BDE8F041022013F029B940 +:103E80000221F8E7BDE8F081474810B50078002826 +:103E900027D13E4CD4E9060100F03BFE94F83110E6 +:103EA000A06A00F05EFDFFF783FF3648006890F8D7 +:103EB0006003C10715D0810713D50024400915F010 +:103EC00015FB00B10124394801788C4209D00470F7 +:103ED0000CB1082100E01021BDE81040032013F0D0 +:103EE000F8B810BD2DE9F0412648284E264C006850 +:103EF000B16990F8315090F8307039B1264884F8A3 +:103F00003050C2386A00206115F053F9F16939B1B7 +:103F1000214884F8317098387A00606115F049F9C9 +:103F20001B481C490078097808438006AAD51A481E +:103F30004C38E0606A00716ABDE8F04115F039B9AB +:103F4000A0E770B50F48114E0F4C0068716B90F8E8 +:103F5000312090F8305031B184F8302014485200AC +:103F6000A06315F026F9B16B002909D0104884F838 +:103F700031502A306A00E063BDE8704015F019B98D +:103F800070BD00000407100068761000800A100061 +:103F9000F4041000F80410000E0801203C07100083 +:103FA000F0041000E8041000E9041000C804100038 +:103FB0003E090120174810B5174904780020086011 +:103FC00000F086F800F0CAFB052C1AD0062C18D099 +:103FD0001249012008701248006890F8700000072C +:103FE00006D41048016821F0020141F0040101608B +:103FF000012105200EF0E4FC4FF48071002013F045 +:1040000068F800F0E1FD0221BDE81040012013F046 +:1040100060B80000E8041000EC0410004B0710002A +:104020000407100014071000554910B50978002442 +:104030000122012909D0C10713D05249032409687C +:1040400091F85032DB070BD106E04F480078012889 +:1040500001D14E48027010BD91F88012C90700D0FE +:104060000B24400703D54A4844F480740270002CA6 +:10407000F1D0FCF7C3F94748016821430160FCF720 +:10408000BBF9012105200EF09BFCBDE810404FF468 +:104090008071002013F01DB810B5C00717D0394843 +:1040A000006890F8C101010601D440060FD5FCF765 +:1040B000A5F93948016841F008010160FCF79CF955 +:1040C000BDE810404FF48001002013F002B810BD8D +:1040D00010B500F079FD0221012013F026F801202F +:1040E00013F097F840212D4815F004F92B490120D1 +:1040F00081F82C0013F0A8F80121022012F0E9FF4A +:10410000BDE8104000F023BB70B52548254E05687A +:10411000306890EA050426D055B160B104EA050084 +:104120000446FFF7B9FF2046FFF77EFF356070BDFC +:10413000FFF7CEFFFAE700F047FD0221012012F061 +:10414000F4FF00F0F3F800F0FAFA2C402046FFF7F5 +:10415000A3FF2046FFF768FF00F0DEFA02210120EE +:1041600012F0B7FFE2E7002DE1D10F4800780528F3 +:1041700001D00628DBD13560BDE87040A8E700001B +:104180004A07100004071000C40610004C07100076 +:104190003807100014071000280710006876100078 +:1041A00030071000EC041000E80410002DE9F04185 +:1041B000FF4800242646006890F84010C90739D00F +:1041C000FC4F3978022912D0042903D005290BD0DD +:1041D000062909D090F841500DF091F802460021CF +:1041E000F548012A0BD028E090F84350F4E790F806 +:1041F000425090F89000C006EED50126ECE73A78E0 +:10420000052A1AD00A460160AA4213DDEB4A137848 +:10421000BBB1016011703878052818D000F0BFF8E4 +:10422000044600F0C2F8044300F0CDF8044300F067 +:10423000D8F804432046BDE8F0810268521C0260B1 +:10424000E2E716B101201070E5E70160E3E7012421 +:10425000F0E710B501464022D94814F0EFFF0121E4 +:10426000BDE81040084612F034BF2DE9FF47D148A1 +:10427000007802281CD0032816D0CD4EDFF84493D6 +:10428000DFF844A301274FF00408052814D00628BE +:1042900068462DD000F046F9CC480090684612F0F0 +:1042A0008CFB04B0BDE8F087684600F0FCF8F3E74B +:1042B000684600F0B2F8EFE7684612F059FBFFF7E6 +:1042C00075FF04464025C0070BD0306890F8700099 +:1042D000000704D500F093F88DF8040001E08DF894 +:1042E0000480E00601D58DF806708DF808700FE0A7 +:1042F000002412F03DFB3068012590F870000007A3 +:1043000004D500F07CF88DF8040001E08DF80480FD +:10431000C9F80040CAF80050BEE710B500F054FCE0 +:104320000221BDE81040012012F0D3BEA2490020B6 +:1043300008607047A04900200860704738B5002029 +:1043400012F067FFA248006810B100F051FA01E0D6 +:1043500000F011FA9748007800F043F90446AFF2F4 +:10436000450100F029FC2046FFF77FFF01280ED110 +:1043700001216B460022084612F0F4FE0121084696 +:1043800012F0D3FE8E48007830B10EF02CF8BDE864 +:104390003840002012F058BFFFF776FDF7E78D4850 +:1043A0000078C00700D0012070478A480078C00715 +:1043B00007D07F48006890F85002C00701D0102055 +:1043C00070470020704783480078C00707D07848BE +:1043D000006890F88002C00701D0102070470020CC +:1043E00070477C480078400707D57148006890F80E +:1043F0000E0BC00701D008207047002070476C49A1 +:104400000120096891F8E710090603D57248407841 +:1044100008B103207047022070472DE9F04105469E +:10442000002712F0A5FAFFF7C1FE04466948DFF83D +:1044300080810078C00708D1D8F8000090F8F0011A +:1044400014EAD01F02D0E00600D44027FFF7C9FFCE +:1044500040EA070644EA0607F8070CD0D8F800003F +:1044600090F8F00114EAD01F02D054480078C0B18F +:10447000FFF7C5FF287171074FF0010000D5687183 +:10448000E10600D5A871710600D52872B10600D5E5 +:10449000E871390700D5E8724A4804604A48066066 +:1044A000C9E60920E6E72DE9F041044612F060FA7A +:1044B000FFF77CFE0646FFF772FF0546FFF775FF24 +:1044C0000543FFF780FF054300F0BAF80543FFF707 +:1044D00088FF40EA050700F0C1F840EA070546EA10 +:1044E0000507F8070BD03248006890F8F00116EA8B +:1044F000D01F01D0092001E0FFF781FF207169077B +:104500004FF0010000D56071F90600D5A071A90631 +:1045100000D5E071390700D5E0722A4806602A48C4 +:10452000056088E62DE9F041064612F021FAFFF712 +:104530003DFE0446FFF733FF0546FFF736FF054310 +:10454000FFF741FF054300F07BF8054300F086F8D4 +:104550000543FFF746FF05431D480068810602D565 +:104560000024012503E0400601D50024102544EA7B +:104570000507F8070BD00E48006890F8F00114EA20 +:10458000D01F01D0092001E0FFF739FF3071790712 +:104590004FF0010000D57071F90600D5B071A90681 +:1045A00000D5F071390700D5F0720648046015E0B7 +:1045B00004071000E8041000CC041000E904100007 +:1045C000800A1000F8041000F404100003420000F8 +:1045D0003C071000EC04100040071000264805605E +:1045E00029E638B52549801E0528096813D2DFE879 +:1045F00000F00306090C0F0091F873400CE091F8ED +:10460000724009E091F8714006E091F8744003E0CF +:1046100091F8754000E0012400250DF055FC00B133 +:1046200001256946032012F08EFD009800B91DB1E6 +:10463000142C01D2142401E004B90124204638BD11 +:104640000F480078C00707D00C48006890F8F001C8 +:10465000C00701D004207047002070470848007848 +:10466000C00707D00548006890F81002C00701D0C5 +:104670002020704700207047F40410000407100049 +:10468000EC041000834810B5006890F87000C00773 +:104690000BD014F07FFF012804D07F48017829B1A6 +:1046A000407818B17D490020486010BD012010BD40 +:1046B00010B5FFF7E7FF012814D100F027FA88B9F9 +:1046C0007748764C00886168401C00EB8000B1EBB5 +:1046D000400F07D914F05EFF012801D0012010BD62 +:1046E00000206060002010BD10B500F0A6F900F0B9 +:1046F00007FA6A49002048606A490220087010BD24 +:1047000010B500F09AF900F0FBF964490020486008 +:1047100064490320087010BD10B500F08EF900F058 +:10472000EFF95E49002048605E49042008705E4948 +:10473000012008705D4908705D49087010BD574937 +:104740000020486070475549002048607047534931 +:1047500000204860534901200870704710B500F0F0 +:1047600069F94E49087000F068F900F0C9F94D493F +:104770000520087010BD70B54A4D484C2878801E41 +:10478000042830D2DFE800F017060229BDE87040A7 +:1047900000F059B800F045F801281BD06068401CB3 +:1047A0006060FFF785FF012802D000F042F80FE0BB +:1047B000BDE8704098E700F034F801280AD03D4881 +:1047C0000078012806D06068401C6060FFF75AFF3F +:1047D000012808D0BDE870409EE700F02BF908B131 +:1047E000217809B1207070BD20700620287070BD3E +:1047F00000F0600151EAC0722A4901D0042002E0B1 +:10480000820702D5032008707047420701D50220B5 +:10481000F9E7020701D50520F5E7C006F4D5062023 +:10482000F1E710B500F006F904460CF068FD2043EE +:1048300010BD1848006890F87000800701D501206D +:1048400070470020704710B5FFF7EBFF134C0128AD +:104850000BD018480078012807D06068401C6060C1 +:10486000FFF7E7FF012803D00DE00020606010BDD6 +:1048700008486168006890F878000A30884202D2DF +:10488000BDE810403CE7FFF713FF0128EFD1BDE87A +:10489000104029E704071000D0061000D0041000D3 +:1048A00048071000E80410004407100045071000F6 +:1048B00038071000460710002DE9F0418B4C0746E1 +:1048C0000E462068002590F8982089480FF0CFFD0B +:1048D00002008848294640D002780125521CD2B2F5 +:1048E0000270236893F89930934237D20170804860 +:1048F000760032463946543814F05BFC7C48324628 +:1049000039462A3814F055FC7B4F3878052825D0D5 +:104910002068032690F85012C90703D190F880024E +:10492000C00700D00B26FBF769FD744801683143CE +:104930000160FBF761FD3878052804D1206890F804 +:10494000EB03C00603D5202105200EF039F84FF403 +:104950008071002012F0BDFB00E001702846BDE828 +:10496000F0812DE9F05F060059D0624C0025DFF898 +:104970008891E5702F4699F80000AA46022803D0D6 +:10498000032801D0052849D1B4F904503046A27853 +:10499000294600F065F8DFF85481A070D8F80000CF +:1049A00090F89000800704D530462946FFF784FF31 +:1049B000074600214E4B08464FF0010BD8F8002067 +:1049C0000FE000BF33F91060B2F892C0664506DD13 +:1049D00092F89160491C8E4201DC5D4604E0401C67 +:1049E000C0B2A842EEDB554699F800004E460228B8 +:1049F00001D0032802D114F0CDFD054375B1307804 +:104A0000022804D0032802D0052804D006E06570EF +:104A100084F803B006E0607800B917B16570BDE8AE +:104A2000F09F657000F0D0F8BDE8F05F0221012032 +:104A300012F04FBB2F48407870472E4800210122CA +:104A400001708270294A126892F8312082802A4AC5 +:104A50001278052A02D0062A00D041707047ECE790 +:104A60002DE9FC418046234814460D464078164601 +:104A700040B91F480A467F234146543800940FF03E +:104A800055FD0026194F386890F89010C90700D0DE +:104A9000ECB117486A0041462A3814F08AFB144AE0 +:104AA0002B46543A02F12A0111480FF0FEFC3868F7 +:104AB00090F89010490707D590F89A3023B10C4927 +:104AC0002A4608460FF04BFD3046BDE8FC81B0F9A0 +:104AD0009610CDE90015064AB0F99430543A414693 +:104AE00002F12A000FF068FCD9E70000040710006B +:104AF000080A0120D8041000E80410001407100070 +:104B00000F480021017041607047F9E70C480078B8 +:104B100070470B4800210278012A01D0416070479C +:104B20004268084B521C42601B6893F881309342E4 +:104B3000F5DA01704160002107200DF041BF00004F +:104B4000E00410000407100008B500F03FF8304CF6 +:104B50006B4600227E21012012F004FB00984107E1 +:104B600003D5FFF7D1FA042119E0010703D5FFF7B8 +:104B700071F8082113E0C10603D5FFF71BFA1021D5 +:104B80000DE0810608D52078052801D0062801D13E +:104B9000FFF710FA202102E0410604D54021012050 +:104BA00012F0C3FAD4E78007D2D50221012012F017 +:104BB000BCFAFFF7C3FBCBE700EB80004FF6FF72B8 +:104BC00002EA400014F06CB814F08CB810B5104C28 +:104BD000002001216060A06021700E4960700870A3 +:104BE0000D4908700D490870FFF739FFFFF78DFF79 +:104BF000FFF7A0FBFFF7A7FD0948006890F8400306 +:104C0000C00703D0A06840F00200A06010BD000003 +:104C1000E80410004A0710004B0710004C07100072 +:104C20000407100001F030B94548407800280DD045 +:104C30004448454990F82C0091F82C10C84205D101 +:104C40000123424A40493F4800F0D5BC704770B547 +:104C50000024012390F82C5008E0C61896F9216032 +:104C60008E4202DB964200DC641C5B1C9D42F4D247 +:104C7000012C01DC012070BD002070BD2DE9F04346 +:104C8000994600231F4647F6FF764FF0FF3C01256B +:104C900090F82C400DE000BF00EB050898F921804A +:104CA000884505DB904503DC431993F9213002E088 +:104CB0006D1CAC42F0D2641C0AE0051995F9215034 +:104CC0008D4205DB954203DC204490F9217001E020 +:104CD000641EF2D1BB4209D10AE000BF39F91300CA +:104CE000B04202DA06464FFA83FC5B1CBB42F5DD9C +:104CF0006046BDE8F0832DE9F04117460E460446B4 +:104D0000C27881780F48FFF7A2FF050006D1E2784C +:104D1000A1780F4B0B48FFF7B1FF30706278217814 +:104D20000948FFF794FF060006D162782178094B05 +:104D30000548FFF7A3FF387005EA0600BDE8F081DB +:104D4000A8511000B023100008241000682610009D +:104D5000D00C0120FA0C0120FE480021FE4B01700E +:104D60000122C1601A7041708170018170472DE984 +:104D7000F04F8246DDE90A09012547F6FF779B4699 +:104D8000AC46FE430446DDF824E014E032F814306B +:104D900031F81480A3EB08031BB2BB4200DA1F46B4 +:104DA000B34200DD1E46002B02DD4FF0000C02E096 +:104DB00001DA4FF00005641EE8D225B1BCF1000F06 +:104DC00001D0002309E055EA0C0306D025B9BCF157 +:104DD000000F01D0334600E03B4600273D465FEA26 +:104DE000090402D00124861E01E00024461ECEF1F3 +:104DF000000910E032F814C031F81480ACEB080C54 +:104E0000ACEB030C0FFA8CFCDC4503DACC4501DD7E +:104E100067446D1C641CB442ECD905B9012597FBAD +:104E2000F5F21A4405E000BF31F8103013442AF8B7 +:104E30001030401EF8D2BDE8F08F2DE9F047002574 +:104E4000894629462F462E46A8462B460DE000BF30 +:104E500030F913C039F913400CFB0C660CFB0477D6 +:104E600004FB0488654421445B1C9342F0DB87FB10 +:104E7000020485FB013CC71A86FB020385FB05651E +:104E800064EB0C04B0EB060C63EB050688FB020335 +:104E900081FB0121851A63EB01086421A7FB010353 +:104EA00004FB0131002207FB02113346624614F075 +:104EB0005CF90246A2FB070301FB073102FB041168 +:104EC0002A46434614F051F9002C00DA4042BDE86E +:104ED000F08770B503460020024601EBD17408E06C +:104EE00003EB420633F91250B6F90260AD1B2844B9 +:104EF000521CB2EB640FF3DB621008E003EB4205D7 +:104F000033F9124035F9025C641B2044521C8A427A +:104F1000F4DB70BD2DE9F0418E4C00208F4DA07068 +:104F2000607028684FF0010790F80F0BC00736D06B +:104F30008B4E8C486169327800F045F928683278E8 +:104F40008849A84600F53460FFF777FF05463178B9 +:104F50008448FFF7BEFFD8F8001091F8282BAA422A +:104F600004DAB1F8262B824200DAA770322D14DD64 +:104F70007C4AB2F90000002800DA4042B1F8101B68 +:104F800088420ADD307802EB400030F9020C00283C +:104F900000DA4042884200DD6770BDE8F081724E61 +:104FA0007048216932782A3800F00DF96D49286877 +:104FB00032782A39A84600F53460FFF73EFF0546EF +:104FC000684831782A38FFF784FFD8F8001091F844 +:104FD000282BAA4204DAB1F8262B824200DAA77005 +:104FE000322DDADD5F4A2A3AB2F90000002800DAF1 +:104FF0004042B1F8121BC3E72DE9FE4F574D8946D9 +:10500000DFF850812968934698F8002091F82B1B0F +:105010000C9E0C099A46012A01D101F00F04524F4F +:105020000096014623463A7850480FF065FA234629 +:105030004B4C4E480096227849462A300FF05CFAD5 +:10504000286890F80E1B49071BD5B0F9181B0123DF +:105050003A788DE80E004549B0F9163B5A460846A5 +:10506000FFF785FE286800232278B0F91C1B8DE825 +:105070000E003E49B0F91A3B2A3152460846FFF766 +:1050800076FE3448022110300BF02EFC314802210C +:1050900014300BF029FC3B785A4634494646D8F880 +:1050A00010000FF002FA3149237852462A31706914 +:1050B0000FF0FBF9286890F80E0B000701D5FFF7F9 +:1050C00029FF2448022110300BF071FC21480221F5 +:1050D00014300BF06CFC25493B785A4601F1760000 +:1050E0000FF0E3F9237803B05246BDE8F04F1F49B3 +:1050F0002A3101F176000FF0D8B92DE9F843804646 +:105100001548144C002605780F462670032012F02F +:1051100080F8174B174A394640460095FFF76CFF59 +:10512000032012F091F80D48134D4FF48077016879 +:1051300091F80F0B420602D5A278012A24D02681CD +:1051400080061CD507497639A1F12A0000F053F8F2 +:10515000012813E0FC0410003807100004071000B9 +:1051600086061000480B012085061000320A012037 +:10517000A06F0120766F01201407100015D000F0F9 +:1051800064F82070BDE8F8832289521C12B2228193 +:1051900091F8291B01F00F019142D1DA268128688C +:1051A000432140F48070286004E02868412140F4E5 +:1051B0008070286005200DF003FC3946BDE8F843F7 +:1051C000002011F086BF30B547F6FF73002405E0DC +:1051D00031F91450AB4200DD2B46641C9442F7DBDE +:1051E000002405E031F81450ED1A20F81450641C26 +:1051F0009442F7DB30BD2DE9F041324C0F460025DB +:105200002168B1F93B2B304909780FF030F9064697 +:105210002068B0F93B2B2D48017838460FF027F96C +:10522000014600222A48012E01D1012902D0C26084 +:105230002846B2E6C168491CC160236893F83D3B2B +:105240008B42F5DA0125C260F2E72DE9F0411D4FEE +:105250001F4C00253868B0F9122BA280B0F8101B43 +:10526000E18090F8223B184801781A4800F017F8BE +:1052700006463868B4F9062090F8223B13480178B6 +:1052800014482A3000F00BF8012E06D1012804D171 +:10529000607810B9A07800B9012528467DE670B580 +:1052A00000252C4606E000BF30F91460964200DD70 +:1052B0006D1C641C8C42F7DB9D4201D9012070BD3E +:1052C000002070BD0407100085061000860610003F +:1052D000FC041000A80A012010B55821FD4814F064 +:1052E00009F8FC485821583014F004F8F948002116 +:1052F000B030C0E90011C0E902111030C0E900115E +:10530000C0E902111030C0E90011C0E902110846DD +:10531000F149086010BD2DE9FF5F06468946EF4858 +:10532000EF499846007809681446012850D0B1F931 +:1053300086A291F88852B1F98272114648460FF060 +:1053400060F98346214648460FF079F900903946C6 +:1053500058460DF076FF0FFA80FB394600980DF0A5 +:1053600070FF00B2ABEB00006843642190FBF1F0EA +:10537000384405B2A8F80850701C00210390C8F802 +:105380000010C8F80410B9F90000A84202DD039922 +:105390000120087009EB4400761C30F9022C311909 +:1053A000AA4202DD012201F8012CB9F9023003EB17 +:1053B0000A0212B2AB4218DDB9F90030934203DDA4 +:1053C000B9F9043093420ADC039B01225A700CE0C5 +:1053D000B1F96AA291F86552B1F96672ADE7D8F8F1 +:1053E000006046F00206C8F8006030F9043CA4F101 +:1053F000020B03EB0A0212B2AB4216DD30F9063C97 +:10540000934203DD30F9020C904203DC012001F8E5 +:10541000020C0AE0D8E900645A460120002113F08A +:1054200091FE06430C43C8E90064022458E000BF23 +:1054300039F91400A84252DD09EB440102915044AD +:1054400031F9021C00B2814204DD029AB2F9022055 +:10545000824210DC029A32F9042C824204DD029A64 +:10546000B2F90220824206DC814235DD0299B1F9AF +:105470000410814230DDD8E9006722460120002176 +:1054800013F060FECDE9000106430F43621E0120C8 +:105490000021C8E9006713F055FE02460B4606EAF4 +:1054A000020007EA0301084319D0029839F91410E1 +:1054B00030F9020C814209DA96439F43C8E900673C +:1054C00003990120214401F8010C08E0DDE90010F6 +:1054D0008E438743C8E90067039901200855641C7F +:1054E0005C45A5D3BDE8FF9F2DE9FF4F81B0824603 +:1054F00000211D4683F82C100B2090464B1E794C42 +:1055000008E0002229188A7581F8213005EB400156 +:1055100022880A80401EF4D2704801787048012920 +:10552000006806D0B0F984224FF0000B5946584667 +:1055300016E0B0F96822F7E70AEB00035C7874B173 +:105540001AF800400CB9491CC9B25970029B33F9D2 +:105550001030934203DD01238B4043EA0B0B401CC8 +:105560004045E9D3604800900E984FF000094C4642 +:10557000C0E9009938E000BF0AEB0400427892B31A +:105580000121914011EA0B0F02D1002141702AE064 +:105590001AF8041039B909F1010101F0FF09524963 +:1055A000009105F8194080F801900E9822460021DC +:1055B000D0E90067012013F0C5FD06430E980F43A4 +:1055C000C0E9006705EB0900817D491C817505EB89 +:1055D00049014C700299009A31F91410914202DD90 +:1055E000009180F82140641C4445C5D385F82C9077 +:1055F00005B0BDE8F08F2DE9F84F0C4605461E4674 +:1056000091461721394813F053FE2821384813F0EA +:105610004FFEDFF8E0A0384F09F108089AF80010B3 +:1056200076B10A4605F1300334493048FFF773FE7E +:1056300004F130033A7832492D48FFF76CFE11E04F +:105640004A462A4800F0E9F842463978284800F0EE +:10565000E4F80020C5E90C00C4E90C0029480088E2 +:1056600028872087284E288F2B4626F8110F208F59 +:105670007080CDF800909AF8002020491B48FFF771 +:1056800033FFCDF8008023463A781D491848FFF7CC +:105690002BFF95F82C10307961F30300307194F8EA +:1056A0002C1061F307103071BDE8F88F70B50C4C09 +:1056B000206890F83012090743D514490A780AB9CE +:1056C000497831B105490978012921D0B0F8421251 +:1056D00020E036E0B023100014051000260510006D +:1056E00004071000C89501000080FFFF860D01200F +:1056F0009D0D01208506100086061000D00C0120AB +:10570000FA0C01202C05100090550120A851100022 +:10571000B0F8481201220DB2B0F944124B4800F023 +:105720004AFA20680022B0F946124848103000F0CA +:1057300042FA2946BDE8704044480122103800F082 +:105740003ABA42484FF0FF31C0E90011C0E90211F6 +:105750001038C0E90011C0E902112030C0E9001181 +:10576000C0E9021170BD2DE9FF4F83B015460699BF +:1057700091F8461002290CD001290CD03349103978 +:105780008A464FF0000BA97813F032FF8146A878C3 +:1057900032E02E49F4E72D491031F1E702462C782A +:1057A0000120002113F0CEFCCDE900011DE000BF77 +:1057B00019F804100498814216D1DDE90023DAE9D2 +:1057C000000110401940084323D0DAE9026722465D +:1057D0000120002113F0B6FC06400F403E4318D0D4 +:1057E0000BF101001FFA80FB641C6878A042DFDA2D +:1057F00009F1280908F10100E97880464145CDDA30 +:1058000006995FEA0B00A1F826B000D0012007B08E +:10581000EFE6002009F80400E6E72DE9F04791469D +:10582000451C0C464FF001080CE0D9E90067224600 +:105830000120002113F086FC06400F403E4301D0BA +:1058400005F80480641EF0D2BDE8F08770241000D3 +:105850009D4A10B513680021B3F81422824205DA7C +:1058600093F81022520701D5022108E0B3F8122262 +:10587000824204DA93F81002800700D50121934890 +:10588000934C4278914214D1A17891420DD0914B22 +:105890001B781A43904B1B781A4307D04168491E66 +:1058A0004160002901DC4078A07010BD4170416862 +:1058B000F7E759B1022901D1012A07D093F818223C +:1058C00042604170002AF0DCA17010BD93F81922EB +:1058D000F6E770B5814A824B7D4D16787A4A9C79FD +:1058E00000211268AB78012E02D17E4E36784EB17F +:1058F000B2F81462864217DA92F81062760713D56E +:10590000022125E0B2F81C62864203DA92F81062A6 +:105910007607F5D4B2F81A6208E000BF92F81002D8 +:10592000800705D5012113E0B2F812628642F5DB4B +:1059300073B168480078012803D0674800780128CF +:1059400003D192F81002000701D5012C00D11946AD +:105950005E4834B119B100BF92F819224260A970B3 +:1059600070BD0029F8D1002BF6D04468002CF6DD7C +:1059700092F810120A0755494968A1F1010102D5B0 +:10598000594A127802B141601946E8E74E484F493A +:10599000006890F81002C2064FF0000003D44C4A91 +:1059A0009070487048600870704710B504464648CB +:1059B000006890F81002C006204602D5FFF789FF64 +:1059C00001E0FFF745FF424882784848417B62F397 +:1059D00007114173A0F82F4010BD2DE9FC5F8346ED +:1059E000434800250A46067800782F4641002C4699 +:1059F000012A17D0DFF8D0A0DFF8F880DFF8F890A0 +:105A0000DAF8000090F81022920610D5B0F92012B2 +:105A1000CDE90016B0F91E324246594648460EF00E +:105A2000CBFC09E033484C3813F042FC42E00A4614 +:105A30005946314813F0BDFB2E484C3835E000BFC5 +:105A400038F9142039F91410511A00D54942DAF8FE +:105A5000003009B293F8102252060BD5204A9279F1 +:105A6000012A07D1254A127822B9B3F822228A42A4 +:105A700000DA012730F914208A4202DA93F816324C +:105A800001E093F817325A43C3F5807301FB0321F9 +:105A9000CA1701EB1261091220F8141030F9141022 +:105AA000A94200DD0D46641C24B2B442C8DB28467E +:105AB000FFF77BFF720059460E4813F07AFB03484C +:105AC0000770BDE8FC9F00000407100018051000D7 +:105AD000400710008C061000240510008D061000F1 +:105AE000A85110008E06100092061000905501205B +:105AF00085061000E00B01202C0C01203805100059 +:105B00002DE9F04F8146DDE909B5012047F6FF7721 +:105B10009A468446FE432C4615E000BF32F8143006 +:105B200031F81480A3EB08031BB2BB4200DA1F4616 +:105B3000B34200DD1E46002B02DD4FF0000C02E0F8 +:105B400001DA4FF00000641EE8D220B1BCF1000F72 +:105B500001D0002309E050EA0C0306D020B9BCF1C3 +:105B6000000F01D0334600E03B4600273C46284664 +:105B7000CBF1000C0EE000BF32F8106031F810805D +:105B8000A6EB0806F61A36B2564503DA664501DD7D +:105B90003744641C401EEFD204B9012497FBF4F093 +:105BA000184404E031F81520024429F815206D1E30 +:105BB000F8D2BDE8F08F2DE9F04115460E460446B7 +:105BC00003460A46FE480178FE4800F099FCFE486C +:105BD00004F108031F460178FA4832462A3000F0E3 +:105BE0008FFC002D07D0204613F0E4FC3846BDE8BA +:105BF000F04113F0DFBCBDE8F0812DE9F00FF3496F +:105C00008246DDE909400968089E914691F82B1209 +:105C10004FF0000B01F0030C012801D0002236E008 +:105C200000200BE004FB00F103EB4102DAF8005026 +:105C30001560BAF80410401C918000B26045F1DB99 +:105C4000A6F800B0BDE8F00F704700BF3AF91200A7 +:105C5000B6F900500146002712E000BF04FB0528FA +:105C600033F91880884500DA4146804500DD40461A +:105C7000002D02DD6D1E2DB200E002257F1C3FB21B +:105C80006745EBDB401A29F81200521C12B2A242FF +:105C9000DCDB47F6FF71002007E000BF39F9102078 +:105CA0008A4200DA1146401C00B2A042F6DB002016 +:105CB00007E000BF39F81020521A29F81020401CC4 +:105CC00000B2A042F6DBB6F90000022802DA401C5E +:105CD000308001E0A6F800B0B6F900006200604331 +:105CE0005146BDE8F00F03EB400013F062BA30B547 +:105CF000002B0DD1B54B1C6894F82832B4F829421A +:105D00009D07B34B04FB04F41B6802D59C4208DCDE +:105D100030BD9C42FCDDAF4B9C7814B95B78002B06 +:105D2000F6D000230AE000BF30F9135031F91340D8 +:105D3000A54201DA20F813405B1C1BB29342F3DB4F +:105D400030BD2DE9FE43804617468946032011F0F9 +:105D500060FAA14C9A4D00979A482A7841467638C5 +:105D600023680EF0C9FB984E009796483278494652 +:105D70004C3823680EF0C0FB944C206890F8301229 +:105D8000C9071AD02A78B0F93412CDE900128D492A +:105D9000B0F932327639914A0846FFF7B1FE2068F1 +:105DA0003278B0F93812CDE900128649B0F93632AE +:105DB0004C398B4A0846FFF7A3FE82492B78874A65 +:105DC000763980480EF071FB7E4933784C39844A2D +:105DD00001F176000EF069FB206890F830128A0716 +:105DE00004D4804A12788AB149070FD5754990F8D2 +:105DF00041322A7808460EF0B2FB206871493278A9 +:105E000090F841322A3108460EF0A9FB206890F83C +:105E10002802C10733D0400701D56A4800E0404658 +:105E20002978714ACDE90021704B029703F5B172D0 +:105E30006A49FFF7E2FE3B462A786D496148FFF761 +:105E400056FF206890F82802400702D55D482A30A6 +:105E500000E048463178644A644B921CCDE9002149 +:105E60007E33029703F587725D49FFF7C6FE6049EE +:105E700054483B4632782A312A30FFF738FFBDE8D4 +:105E8000FE43032011F0E0B970B5574C5949083C66 +:105E90000025A571012008704C48257165710068C6 +:105EA000B0F83A02A08100F07EFB2561656170BD0B +:105EB0002DE9F0410E464F494B4C07460D78002026 +:105EC000083C0870607100F06EFB2A463146384687 +:105ED000FFF737FF3F4841783C480029A17915D0AA +:105EE000012919D00068B0F93C12414DA1817635E5 +:105EF00001222846FFF75FFED5E9000108430FD0D5 +:105F0000D5E9020108430BD001200AE0012903D0A2 +:105F10000068B0F93A12E8E70068B0F97812E4E7EF +:105F20000020207167E62DE9F34F834632480027B1 +:105F300040F6FF7401782548A7B02546006801297E +:105F400009D02849097849B12C490978012908D094 +:105F500002290BD00EE0B0F959420BE0B0F95242E1 +:105F600001E0B0F95442B0F9CE5B03E0B0F954421D +:105F7000B0F9D05B124801214FF0000E0078204E9E +:105F8000801E00F0FF0910480278931E03F0FF08FE +:105F90000BEB42039A460CE0704605E033F910C063 +:105FA000B44500DD6646401C4045F7DD03EB420387 +:105FB000491C4945F0DDDFF810805200514621E0D0 +:105FC00085061000D00C0120860610000407100082 +:105FD000BC0610004007100038061000006F0120BA +:105FE0002A6F0120380510002805100090241000A9 +:105FF000F2251000450710003E051000390510007D +:106000000080FFFF684613F0D4F898F80000414282 +:10601000FE4A6B46128802EB410109B242000BEBCB +:10602000410103EB400013F0C4F898F80000694602 +:10603000420008460EF0B1FA301A289AF44900B22C +:10604000022A05D0A1F85000A84204DD022705E08D +:10605000A1F85200F8E7A04200DD0127ED490A88C7 +:10606000521C0A80EC4A12784A808C80CD800881CC +:10607000384629B09DE52DE9F14FE848E84A4FF050 +:1060800000090068FF261278B0F8D2AB85B0494607 +:10609000354632B1E04A1278012A05D0022A08D0EA +:1060A0000BE090F8D46B01E090F8D56B90F8D65BDC +:1060B00003E090F8D56B90F8D75BDA4801230078BD +:1060C000801E00F0FF0E039003200490D648027853 +:1060D000901E00F0FF0B0290059800EB4204019423 +:1060E00029E0DFF830C39FB204980CF1200C009730 +:1060F0001CE000BF04EB400834F9107038F9048C40 +:10610000B7EB080700D57F423FB257450DDDACF82D +:106110000400DDF80080ACF80680DFF8F882491C46 +:1061200008F13008C9B2A8F80070401C5845E1DDFC +:1061300004EB42045B1C7345D3DDB64803233030C7 +:1061400002EB420481800398C0B2009001200390CA +:10615000029800F0FF0B059800EB440C019C32E024 +:106160004FF0000E039820E03CF9107034F91080D5 +:10617000B7EB080700D57F420FFA87F8D04513DD4B +:10618000A44F2037491CA7F8008038817B813CF858 +:106190001080A7F80C8034F81080A7F80E800EF15C +:1061A000010707F0FF0EC9B2401C5845DCDD9F48CF +:1061B0000CEB420C04EB42040778F046774500D81C +:1061C000474607705B1C00988342C9DDA94201D98C +:1061D000022002E0B14201D9012081468D482030E1 +:1061E0004180484606B0E4E4F0B58A488A4B002274 +:1061F000018A491C01828D494C7844821E7886822E +:10620000CD78C5828F780783A64205D18A70CA707F +:10621000C18B491CC183F0BDDFF800C2B442DCF879 +:1062200000C010D907F10107CA70FDB28D709CF84B +:10623000626206F00F06B542EDD91C708A70418B80 +:10624000491C4183F0BDFDD26D1C8A70EDB2CD704A +:106250009CF86262B5EB161FF4D91C70CA70818B72 +:10626000491C8183F0BD2DE9F047DFF8B891054660 +:1062700099F8000002285DD96D48007818B96D487A +:106280000078012856D06C4E012402213068FFF7B7 +:106290004AFE074603212846FFF745FE05463068BB +:1062A000FFF7E9FE0146AF4201D9284600E0384633 +:1062B000814200D90846614A127802B10020574E47 +:1062C0005A4B326893F8008092F8D8CBC44502D874 +:1062D0000020587002E0587000B100244D48418100 +:1062E0008781C58192F85002000722D599F80020D5 +:1062F00053485449022A1CDB534D531E05E000BF8E +:1063000030F91370AF4200DD3D465B1EF8D1801CB2 +:10631000921E0EF042F93168281A3D4A00B2B1F9D6 +:106320005712A2F85400884203DD3CB10220BDE8B8 +:10633000F0870CB10020FAE70120F8E70320F6E728 +:106340002DE9F04107464148164600240078D8B3AD +:106350003848334D007800B33D4834491031006867 +:1063600000F0EFF82D483149006810310A68B0F8A4 +:106370005F329A4217DDB1F9061090F8610281424E +:1063800011DD3548334AB0F90010384600F05CF9A9 +:10639000044644B100F02EF90CE02C78012914D009 +:1063A0000029F6D1002496B12C49002008702878E5 +:1063B00000B10124FFF718FF294E28783178884270 +:1063C0000CD038B1012106E00DE00124E2E700F035 +:1063D00027F9ECE7002106200CF0F2FA287830705B +:1063E0000CB1012007E4002005E470B50446032049 +:1063F00010F00FFF2046FFF736FF0446032010F091 +:1064000023FF0349C87B64F305102BE096061000B8 +:1064100090550120460D0120390510000407100099 +:1064200038051000850610008606100020051000B3 +:106430003D0510003E051000B4061000D006100007 +:10644000006F01202C0C01200080FFFFA8511000DC +:10645000AC06100068261000340610003C05100041 +:106460003A051000C8735748017821B10021017026 +:10647000204600F062F9544D544821462A790068BC +:10648000FFF75EFFA87170BD70B5514A0024234626 +:1064900012782146521E52B24E4D0DE035F912606F +:1064A000864202DD491CC9B204E08C4200D9214673 +:1064B0000C460021521E52B2002AEFDA8C4200D95B +:1064C0002146454C00222478641E65B2414C2A3492 +:1064D0000EE000BF34F91560864202DD521CD2B2D4 +:1064E00004E0934200D91A46134600226D1E6DB295 +:1064F000002DEFDA934200D91A468818C0B270BD59 +:106500002DE9F0471D464FF00008C5E90088914687 +:1065100082460C4611E000BF3AF9141049450CDDE3 +:10652000D5E900674FF0010822464046002112F0ED +:1065300009FE06430F43C5E90067641EECD24046DE +:10654000F5E630B5254A1268B2F85D22524213B220 +:106550000022CA808A800A60214AB2F9002012E033 +:1065600030F91240002C0EDA8C88641C8C8030F9D3 +:1065700012500C682C440C6030F912409C4202DA34 +:10658000CC88641CCC80521EEAD2164A887982F8E4 +:1065900058000868002800DA4042A2F8590008684C +:1065A0004042086030BD10480021C0E90011C0E938 +:1065B000021108460D4981F82C000D4981F82C0084 +:1065C000704700003D05100020051000AC061000CB +:1065D00085061000D00C012086061000040710006C +:1065E000960610009055012068261000B023100078 +:1065F000082410005748002101710278002A0ED1AA +:10660000C278554B521CD2B2C2701B6893F86232EA +:1066100003F00F03934202D201220270C17070474F +:106620004C480021C1700278002A0CD002794A4BF4 +:10663000521CD2B202711B6893F86232B2EB131F84 +:1066400001D90170017170472DE9F74F86B08B4673 +:10665000D2E90001CDE90201D2E90201CDE904014C +:1066600002A812F0A7FF04A812F0A4FF3B480025DF +:106670002F4606782FE0F1B2069812F0B1FF82465D +:106680003748324600210478012012F05BFD029A5F +:1066900000EA0208039801EA0009DDE90401CDE9F6 +:1066A000000116E03AF91410594512DD58EA0900C4 +:1066B0000DD022460120002112F044FDDDE9002327 +:1066C00010401940084302D07F1CBFB201E06D1C8E +:1066D000ADB2641EE6D2761ECDD2224800F8565FD7 +:1066E00047701D48006890F85B12A94207D890F8DF +:1066F0005C02B84203D3012009B0BDE8F08F00204E +:10670000FAE7144810B5817801700021C170017159 +:10671000FFF7BAFBBDE81040FEF7DEBD0D480021D3 +:106720000D4A017041708170126892F850229207F0 +:1067300000D501218171417170470B490A780549E3 +:10674000012A04D08A79012A03D1002801D100202E +:106750008871704738051000040710008506100086 +:1067600086061000905501204C0710002DE9FF5FB0 +:10677000FF4F0546DDF838B03868984690F8A51206 +:10678000B0F9AC42490607D590F83100FF22C100AC +:10679000F848103112F084FDF748417809B9807843 +:1067A00010B13868B0F9AE420026DFF8C893BA4697 +:1067B00021E000BF02990BFB06F001EB40073946D0 +:1067C0005A4608460CF0C2FC22465B461146384643 +:1067D0000CF0DEFCDAF8002092F8A62212B15B463B +:1067E0000CF0F6FC09EBC602C2E9020105EBC60299 +:1067F000761CC2E900014645DCDBDAF8000090F8BF +:10680000A502400619D500204B46DFF870C310E002 +:1068100003EBC00797E80601FE6801EA0801324071 +:10682000D7E90467314005EBC0063A40C6E90012DB +:10683000401C9CF800108842EADB204604B0BDE80A +:10684000F09F08B5009380230DF046FE08BD70B59B +:10685000B1F90050B2F90060049C75435B1EEE175D +:10686000634305EB5665641EED11A4B2058031F952 +:106870001450B2F902609BB27543EE1705EB5665F2 +:10688000ED1120F8145031F91350B2F9046075433A +:10689000EE1705EB5665ED1120F813502344B2F9BD +:1068A000062031F913105143CA1701EB5261C91187 +:1068B00020F8131070BD08B500931346B04AB2F922 +:1068C00000200DF019FE08BD2DE9F05FAA4DAD4A7C +:1068D00000216B789078DFF8B092022B00D230B1B3 +:1068E00089F80210022B00D208B189F8031099F838 +:1068F00006309246034301D089F804109C4CA3490A +:1069000020680978B0F91873B0F94283062901D1DB +:10691000B0F9167399F8031029B19D490978012936 +:1069200001D1B0F9507390F88B1B090604D5994931 +:10693000097809B1B0F98D7B12F016FE50B12068CC +:1069400090F81B1390F84503394440440FB20FFAF6 +:1069500080F808E06878022805D32068B0F81C1396 +:1069600009B1B0F91C7399F8060080B12068642160 +:1069700090F8690300FB07F200FB08F092FBF1F2CC +:1069800090FBF1F03A44404417B20FFA80F8824E7F +:106990008249834D3780A1F80080206890F81A233F +:1069A000BA1A2A8090F84423A8EB02037D4A138088 +:1069B0007D4B93F800C0BCF1000F02D09B78FB1A0E +:1069C0002B8099F800304BB1784B1B7833B1B0F87D +:1069D0006C32338090F86E72DB1B2B809AF8023099 +:1069E00033B1B0F86C32338090F86E02181A2880F8 +:1069F00099F802306E4823B96E4F33883B802B885C +:106A0000038099F80330CB461BB933880B80298863 +:106A10001180B0F90010B2F90020B5F900000CF0B7 +:106A2000FEFB654FB046DFF8989138803088634EA2 +:106A3000308064482988A9F800100078A8B112F0C5 +:106A400093FD10B1206890F83D042168B1F83A2414 +:106A50001044308091F83C14401A01B2A9F800109B +:106A6000B7F900000CF0E9FB3880574E5749B8F8E9 +:106A700000003080564A0880288810809BF8040067 +:106A80005D46F8B12068B0F8B03923B1AB7913B1E5 +:106A9000B0F8B03904E0B0F8AE3913B1B0F8AE399F +:106AA0003380B0F8B23933B1B0F8B2390B8090F816 +:106AB000B409181A1080B2F90010B7F900000CF0F0 +:106AC000BCFB38803948434F007818B12068B0F8D3 +:106AD000C4020EE09AF802000028F7D12068B0F94D +:106AE000C20238802979002904D0B6F900100CF0D0 +:106AF000A4FB3880A3E62DE9FF4F85B007460821A7 +:106B000012A8149D11F0E8F80490002875DD4FF0EC +:106B1000000ADDE912015646D046D346D146CDF8EB +:106B200004A05446CDF800A0CDE9020115E02246AC +:106B30000120002112F006FBDDE90223104019407C +:106B4000084309D037F9140004FB048804FB0099BA +:106B50000AF1010A26448344641CAC42E7DB08FBCB +:106B60000AF006FB160212B109FB0AF034E05EE0FF +:106B700004071000302710004007100085061000A1 +:106B80009606100040051000A8511000E8041000FF +:106B90009106100046071000280610002C06100071 +:106BA0002E06100032061000D00610003805100026 +:106BB000300610002A0610003406100040061000AF +:106BC0004206100047071000480610004A06100051 +:106BD0004C0610003606100006FB1B0308FB0BF0EA +:106BE00009FB1604002020E003FB004191FBF2F1B9 +:106BF000069EB14202DD314604E02CE0F14201D5AF +:106C00000699494237F81060711A09B227F8101036 +:106C1000079EB14208DA0E44002E05DD019E314484 +:106C200001910099491C0091401CA842DCDBFE4800 +:106C3000006890F8A712049881420CDDDDE900108D +:106C400090FBF1F005E000BF37F81510091A27F89E +:106C500015106D1EF8D209B0BDE8F08F2DE9FF5F69 +:106C6000F24C884600260746924635464FF4667138 +:106C70004046266012F01CFB0021404612F0B8FC92 +:106C800081460021384612F0ABFC0022E84BE94F68 +:106C90002AE000214FF0010EDFF88CB319E000BFAD +:106CA00030F91180D04505DD09F801E030F911C057 +:106CB000761C6544DBF800C030F91180BCF855C380 +:106CC000E04505DDD4F800C00CF1010CC4F800C0AB +:106CD000491C93F800C06145E2DB0CF0FF0109F1AB +:106CE000280900EB4100521C39788A42D1DB039815 +:106CF00005603046A2E505E030F912308B4201DD37 +:106D000001207047521EF7D2002070472DE9FE4F38 +:106D1000C54C8146C84E20684FF0000590F8A5325A +:106D2000DB0607D5C54BB0F8D3021B68404383424E +:106D300000DD356013463268C14E3068FFF7BBFD99 +:106D4000032010F066FA2068BA4F90F84003C0079D +:106D500014D0BC48007888B93978BB480DF05CFC89 +:106D60002168BB4AB1F85833B849984204DCB948A5 +:106D700083780BB9407820B3CD701570B648316870 +:106D8000B0F90030B548026848460DF08EFB05F0BA +:106D900039FE032010F058FA2068A54E90F8A4128E +:106DA000090624D5B0F9B0B2307800904A463B7855 +:106DB0001146AB48FFF7DAFC82460025DFF8A082D7 +:106DC00012E00120C870D9E708EBC5023378D2E998 +:106DD00000128DE80E0003FB05F009EB40005A4657 +:106DE0005146FFF788FE6D1C38788542ECDB206841 +:106DF00090F8A402400708D533783A78494603B0A2 +:106E00000846BDE8F04F00F08FBBBDE8FE8F2DE9CE +:106E1000F0410A4680460026924D3146104612F057 +:106E2000E7FB04460021404612F0E8FB024680489A +:106E3000002103787F4890F800C012E0002009E0AC +:106E4000275C2FB132F91070AF4201DDC6B23D466A +:106E5000401C00B29842F3DB491C02EB430209B22A +:106E600028346145EADB202E01D0212E1FD10721D5 +:106E7000404612F0C3FB6C4C30F9401F6425226879 +:106E800092F8B52A514391FBF5F1428811444180B3 +:106E90000821404612F0B2FB226830F9401F92F8F8 +:106EA000B52A514391FBF5F1428811444180BDE878 +:106EB000F0812DE9F04780465B4899461746056802 +:106EC00069480E460024006805F6A73512F088FBD5 +:106ED000B8EB0702A6EB090100D55242002900DAFF +:106EE00049425018C0B2142800D82C5C2046BDE896 +:106EF000F0872DE9F04704464B485C4A006832F9B8 +:106F0000118000F6C330B8F1000F05DD584D35F99A +:106F100014A0BAF1000F03DC807A4043000AE6E7D0 +:106F200032F8112035F8145002EB82024FEA420980 +:106F3000504A05EB85056F00B2F900C0B2F9026056 +:106F400099FBFCF397FBF6F5C3F10A03C5F10A05BB +:106F5000C35C455D03FB05F0000AC828C7D9518111 +:106F600099FBFCF1A2F80C80C1F10A01D18197FBD9 +:106F7000F6F113825482A2F814A0C1F10A01D18261 +:106F800015835083B3E770B520213A4812F090F989 +:106F9000284A0021354C3748137809E0B0F90050F1 +:106FA00034F91120954200DD2A46491C0280C9B2FD +:106FB0009942F3D31E4A00212D4C13780AE000BFFA +:106FC000B0F9022034F91150AA4200DC2A46491CCB +:106FD0004280C9B29942F3D370BD2DE9F05F8A4671 +:106FE0008346FFF7D0FF0026B146DFF848805AE01D +:106FF0001D483146006812F001FB054600240C4F85 +:107000004CE000BF35F91400002845DD53465A46D0 +:1070100031462046FFF74DFF70B335F91410414358 +:10702000081225F8140028E0040710001C061000C0 +:10703000860610008506100038061000BC061000F9 +:10704000B0061000D0061000006F0120A8511000FB +:107050008F0610004007100096061000B4061000BE +:10706000782610000080FFFFA8061000D00C012039 +:10707000FA0C01200A1401201AE031462046FFF7DD +:1070800038FFA8B135F914104143091225F814103E +:10709000FE498C80CE800881641CE4B2387884423A +:1070A000B0D3761CF6B298F800008642A0D321E552 +:1070B00025F81490F0E72DE9F04700252C46DFF87D +:1070C000D093DFF8D083F44EF44F17E02146D9F87F +:1070D000000012F085FA0021424633780AE000BF32 +:1070E00030F911C0AC4503DD30F811501170547007 +:1070F000491CC9B29942F3D3641CE4B23878844283 +:10710000E4D3F4E62DE9F84F0646E548002592461B +:1071100004788B460570FFF7D7FBDE480221001D7F +:1071200009F0E2FB2246DB4C31466068FFF7EEFDDA +:10713000DC4EDD4F316891F8A402020705D4C00689 +:1071400003D491F8A502C00706D06168B7F90030F2 +:10715000D64A0846FFF775FB3068B14690F8A5029D +:1071600080060AD5CC48D14A00780090CB486168A7 +:10717000083A03780846FFF76AFBB7F90000616830 +:107180004200CB48006812F014F8DFF8288398F822 +:10719000000010B998F8010028B1514658466268BD +:1071A000FEF786FE01E0C4480570B94EB7F900004D +:1071B00061684200306811F0FCFFB6480221001DF2 +:1071C00009F0F5FB98F80000DFF8F0B2C24628B3EA +:1071D0009BF80000012821D1D9F8000090F8A50201 +:1071E00040071BD5A078C8B90120A070FFF76CFB41 +:1071F000012108200BF0E4FBB148007802280DD1F2 +:107200002078009094F80180FFF755FF4046B8F1D0 +:10721000FF0F03D001460098FFF7DFFEA648007875 +:1072200030B19AF8010018B19BF80000022828D06C +:10723000A448B7F90020B0F900103068FFF75BFDF3 +:10724000A149A24FF8B10120087001460224A048CC +:1072500009F04AFBA0489E4D9E4BB0F900202968DA +:107260003068FFF7FBFC3860D9F8000090F8B40AEA +:10727000C00703D029683068FFF7C9FD2046BDE884 +:10728000F88F0420FBE7FF202070607093483D607A +:10729000012405608F4805600D70EFE72DE9F84384 +:1072A00005467F484FF00009047880F80090FFF70A +:1072B0000BFB78480221001D09F016FB2246754C95 +:1072C00029466068FFF722FDDFF8D881D8F8000072 +:1072D00090F8EB13490620D58149DFF808C28F6882 +:1072E0000E68BA1BACF86720CD684B68E91AACF899 +:1072F0006910B74203DDD0F81364B24205D89D424D +:107300000BDDB0F81724914207DD62480221001D11 +:1073100009F04DFB0020BDE8F88390F8A412624DFF +:107320000A0705D4C90603D490F8A502C00706D001 +:107330006168B5F900305D4A0846FFF782FAD8F86F +:10734000000090F8A50280060AD55348574A0078F5 +:10735000009052486168083A03780846FFF777FAC8 +:10736000B5F900004A4E42006168306811F021FF13 +:10737000B5F90000616842004D48006811F019FF3E +:1073800044480221001D09F012FB4E48B5F90020C7 +:10739000B0F900103068FFF7AEFC4B4990B1012006 +:1073A0000870014602244A4809F09EFA4A48494BAF +:1073B000B0F90020464801683068FFF74FFC4349A8 +:1073C000086002E081F8009001242046A3E73149DB +:1073D0003D4A002048601070887000F002B800F04C +:1073E0001AB8304810B500683F49404BB0F8182330 +:1073F0000A80B0F82C133E4C1980B0F84233238039 +:107400003C4C22803C4A11803C490B803249B0F808 +:10741000C202088010BD2DE9F00F224B8024234EBC +:10742000196891F8312091F8305002FB05F001E025 +:1074300026F81040401EFBD291F8A5029A46C007DC +:1074400022D01A4F002301F59C611BE003FB05F0DD +:1074500007EB400C00204FF0640910E00E5C4FEA8F +:10746000C618B8FBF9F83CF9106006FB08F64FEABD +:10747000E67806EB5866F6112CF81060401CA8421E +:10748000ECD35B1C9342E1D33AE000000A140120E4 +:10749000A8061000400510008606100085061000A2 +:1074A000440710000407100096061000CE0D0120BE +:1074B000AC061000A851100024051000260510008D +:1074C00039051000340610008C0610001806100054 +:1074D000E005100020061000360610001C06100003 +:1074E0002C14012090550120280610002A061000B7 +:1074F0002C0610002E061000300610003206100078 +:10750000DAF8000090F8A50280060AD55149032058 +:1075100021F81040401EFBD2BDE8F00F4D4800F0AE +:107520005EB8BDE8F00F70472DE9FF4F83B01E46EF +:107530000F461C464EE000BF012047F6FF79009041 +:107540006FEA09080190059D24E04348224600EBBC +:10755000C5000021D0E900A39B46012011F0F2FDF7 +:1075600000EA0A0001EA0B01084313D005FB0640BC +:1075700037F91000814500DD8146804500DA8046FC +:10758000002803DA4FF00000019003E002DD4FF025 +:10759000000000906D1ED8D2DDE9001008430AD02B +:1075A000019810B130B119B104E019B1404602E0C0 +:1075B000484600E0002041000CD0059908E000BFDB +:1075C00001FB0642039D37F812301B1A25F81230D2 +:1075D000491EF5D2641EAFD207B0BDE8F08F1F4B35 +:1075E00010B5196891F8D512CA016421B2FBF1F403 +:1075F000B0F900206243D41702EB5462D21102802A +:107600001A6892F8D622D201B2FBF1F4B0F9022046 +:107610006243D41702EB5462D21142801B6893F884 +:10762000D722D201B2FBF1F4B0F904206243D4179F +:1076300002EB5462D211828093F8D822D201B2FBBD +:10764000F1F2B0F906105143CA1701EB5261C911AA +:10765000C18010BDC60D012078261000040710005F +:107660008C48002101704180704730B58A4902463C +:1076700001200C6894F81F3A4BB1864DB2F84010C7 +:107680006D68491B00D549428B4200DA002094F80E +:10769000201A002912D07F4CB2F92A500834B2F9CE +:1076A0002820B4F90230B4F900405B1BA21A5B43F6 +:1076B00002FB023249438A4200DD002030BD2DE941 +:1076C000F047754FDFF8CC8106004FF005044FF00E +:1076D000060510D096F8240100F048FA04463868F0 +:1076E00090F81E0A18B1B6F8401081422DD8B06A41 +:1076F00000F0A5F848B398F8000001214FF0000908 +:1077000007280ED2DFE800F00404243C6E040400D5 +:10771000052C04D0042C06D0012C07D015E088F8E5 +:107720000090BDE8F08788F80010FAE7FFF798FFAF +:10773000022088F80000A8F80290B6F84000C8F8C7 +:107740000400B06AC8F80800EBE788F80050E8E7E2 +:10775000B8F80200401C80B2A8F80200032C03D045 +:10776000396891F8191A48E0032088F80000A8F851 +:107770000290D6E7052CD4D03046FFF776FF2EE0F6 +:10778000B8F80220521C92B2A8F80220012C1ED098 +:10779000386890F81A3A40469342C2D8057098F873 +:1077A0000100012801D00328BBD13C48394A41706F +:1077B0001921083281705188C170090A017111883C +:1077C0004171090A8171BDE8F0470BF0FFB83046FE +:1077D000FFF74BFF042288F80020A8F80290002849 +:1077E000B3D09EE7B8F80200401C80B2A8F80200AF +:1077F000032C05D0396891F81B1A8142BAD8A4E746 +:10780000052088F800008CE738B500210091694612 +:1078100000F088F91F4C012802D90620207005E0ED +:107820000098FFF74CFF2078052801D0002038BDD4 +:107830001A480121417005218170012038BDF0B541 +:10784000154906460120096891F81C2A950091F80F +:107850001D2A2B46940091F83620D7074A8E898E30 +:10786000A2EB0502A1EB040112B209B20ED023462D +:107870000F462C463114994206DBB94204DC31B282 +:10788000A14201DB914200DD0020F0BD17460A460F +:10789000F0E700004805100004071000E82710007A +:1078A00000F095BABB4890F82C00062801D00528B6 +:1078B00007D1B948B949006890F8BA0200F00F0042 +:1078C0000860B7490020487000F0B8BA70B5B549F3 +:1078D00000220978062903D011B1052900D0012220 +:1078E000B1490B78AE49012B04D0022B02D0032BF7 +:1078F00000D04AB1A848006890F8790048700A287A +:1079000001D20A20487070BD4A7822B1521E12F08E +:10791000FF024A70F7D105465FF00004C4EB041083 +:1079200000EB441005EBC0063146284604F0CEFAC1 +:107930003146284604F003FB641CE4B20F2CEDD35F +:107940009A4800780528DED0BDE87040102101205B +:107950000FF0BFBB2DE9F0410024054600F580562D +:107960005FF00107D6F8080607FA04F108420AD0CA +:10797000C4EB041000EB441005EBC00000F128013B +:107980000C300BF026FD641CE4B20F2CEAD3BDE8EA +:10799000F0812DE9F0470027814605463C4600F579 +:1079A00080580126D8F8080606FA04F108420CD0DF +:1079B000C4EB041000EB441005EBC00191F8240166 +:1079C000032802D1284604F09FFA641CE4B20F2C6D +:1079D000E8D34846FFF7BEFF754C0020704D20608D +:1079E0006060A060E060A868C00104D5484600F06F +:1079F000D3FD012806D0287A800603D54846FFF734 +:107A000003FF50B9A868C00115D5484600F016FB21 +:107A1000A1781A2907D0182768B165480AF0D6FF5F +:107A2000182F02D005E01A27F6E7614808300AF05F +:107A3000CBFFFFF715FEB0464D46002409F58056F2 +:107A400008FA04F0D6F80816014211D0C4EB04106D +:107A500000EB441005EBC00797F82401082807D174 +:107A60003946284604F06BFA3946284604F02EFAC7 +:107A7000641CE4B20F2CE3D34846BDE8F04725E789 +:107A80002DE9F84F80464448006890F83C0AC0074A +:107A900044D04046FFF75EFF414F4FF00006B86804 +:107AA000C0013DD5404600F010FCDFF8049183464C +:107AB00009F1080000244FF0010A08F580550090F4 +:107AC00028E0D5F808060AFA04F15646084220D004 +:107AD000C4EB041000EB441108EBC10090F87001F6 +:107AE000012803D130488079A04201D0387880B98C +:107AF000BBF1000F0BD02E480AF068FF99F8020086 +:107B00001A2806D03E7000980AF05EFF01E00020BF +:107B10003870641C95F91006A042D2DABDE8F88FDF +:107B20003E70FBE730B5054600200346C3EB031269 +:107B300002EB431205EBC20494F82421012A0DD074 +:107B4000022A0BD0032A09D0042A07D0052A05D01F +:107B5000062A03D0072A01D0082A02D1401CC0B24D +:107B60000C605B1CDBB20F2BE0D330BD09280ED2BA +:107B7000DFE800F00D0505070909090B0B000420DB +:107B8000704701207047022070470320704705208E +:107B900070470000687610000407100038061000D7 +:107BA000580510004805100050281000E804100087 +:107BB000E82710002DE9FC4FFE4AB0F90270B0F939 +:107BC0000660D2F800C0B0F90050B0F904409CF84B +:107BD0003620BCF8323093465FEAC278BCF83420D5 +:107BE0004FEA4B7809D0B8F1000F21DA5D1B1C1B5E +:107BF00065F31F4964F31F411EE0B8F1000F06DA78 +:107C0000DF1B9E1B67F31F4966F31F4103E066F30A +:107C10001F4967F31F415FEA8B7604D5551B65F357 +:107C20000F09141B0FE064F30F0965F30F0111E056 +:107C300064F31F4965F31F415FEA8B7406D5D41BBB +:107C400064F30F09941B64F30F0103E066F30F095B +:107C500067F30F019CF83040551C9CF831C0A046DA +:107C6000B3FBF4F4B5FBFCF524B22DB2002B76D0B7 +:107C7000002A74D0002C72D0002D70D00E144FF05A +:107C8000000B13D096FBF4F767F3070A96FBF4F7A3 +:107C900004FB17661FFA86F64FEA2947BB4209DC48 +:107CA000A8F1010363F30F2AA3B20CE06BF3070AF8 +:107CB0000026F1E797FBF4F363F30F2A97FBF4F345 +:107CC00004FB13739BB209B291B191FBF5F767F313 +:107CD000174A91FBF5F705FB171189B20FFA89F7DF +:107CE000BA4209DCACF1010262F31F6AAAB20CE0ED +:107CF0006BF3174A0021F1E797FBF5F262F31F6A75 +:107D000097FBF5F205FB127292B201EB810106EBD3 +:107D100086064900760003EB830391FBF5F15B00D7 +:107D2000C1F10A011FFA81F902EB820196FBF4F618 +:107D300093FBF4F3490091FBF5F1C6F10A061FFA33 +:107D400086FE9BB20AF0FF028FB200259346CAF36B +:107D500007444FEA1A66CAF3072C009325E034E083 +:107D6000934502D10FFA8EF807E0944503D10099AC +:107D70000FFA81F801E04FF00A083BB221460FFAF2 +:107D800089FA01930DE08C4201D1534604E08E4202 +:107D900001D1019B00E00A2308FB0353491C1DB2DB +:107DA00009B28E42EFDA521C12B29445D8DA8581BC +:107DB00080F808B080F809C0A0F810E0009941826E +:107DC0008472C672A0F81490C782BDE8FC8F7A480E +:107DD00010B5007828B9794800218163C163A0F803 +:107DE0004010744C7548216891F83D2AC28191F881 +:107DF0003E2A8276B1F83F2A4280B1F8432A0280B7 +:107E0000B1F8412AC280B1F8452A828091F8472A08 +:107E1000027691F8481A4176FFF7CCFE67491C229A +:107E200001F11C0011F0C5F9216864481C3091F87B +:107E3000492A027691F84A1A417610BD5E480078C8 +:107E4000002811D15D495D4A8863C863A1F84000EC +:107E5000383108705748006890F8471A117602F1D7 +:107E60001C0190F8490A087670472DE9F041044654 +:107E700090F8337190F8246190F825510B2084F824 +:107E80003301082084F82401052084F825012046C8 +:107E9000A16A0AF0A7FD84F83371474984F8246188 +:107EA00084F8255100200870BDE8F0812DE9FE4FCF +:107EB000064643480C46002180F82F1004F11000BC +:107EC0000290A08904F1080808B947F6FF704FF046 +:107ED000000B0190DA46D94696F8667031E000BF93 +:107EE00098F80200B8422BD898F80300B84227D37C +:107EF000F9B2344811F07CFB009096F864501BE016 +:107F000098F80000A84216D898F80100A84212D3A9 +:107F10000098405D78B1F9B2E8B24246029B00F0A9 +:107F20005BFB58441FFA80FB0098405D18B109F1D3 +:107F300001001FFA80F96D1C96F86500A842DFD297 +:107F40007F1C96F86700B842CAD264200BFB00F190 +:107F50000198B1FBF0F082B2B6F8440028B1642376 +:107F60004343B1FBF3F11FFA81FA96F8701101292E +:107F700003D11349012381F82F3011490872000AF7 +:107F8000487281F80A904FEA1920C8720E48019988 +:107F900020F85D1FA0F802B0B6F84410C180A0F828 +:107FA0000890027180F805A0207E904212D8617E70 +:107FB00051450BE004071000C406100018281000FB +:107FC000E8271000D41701209055012002D8012085 +:107FD000BDE8FE8F0020FBE72DE9F04190F8242159 +:107FE0000024032A01D0042A26D1FF4AB1F9023025 +:107FF000126892F84C5A5B1BB0F92A50AB421BDC5A +:10800000B1F9003092F84E6A9E1BB0F928309E42BA +:1080100012DCB1F9066092F84D7A3E44AE420BDBB9 +:10802000B1F9045092F84F2A2A449A4204DBFFF730 +:108030003DFF012800D10224204635E72DE9F05FFD +:10804000DFF8A8938046002799F800300126A9F1AF +:108050003800DBB1E5494D46DFF894A38979DFF8B4 +:108060009493C1EB011202EB4111024608EBC104EB +:10807000927E4FF0040B04F12801012B3CD0022B1F +:108080007ED0032B7DD0042B7CD049E0002408F562 +:10809000805583461BE000BFD5F8080606FA04F1B8 +:1080A000084212D0C4EB041000EB4411CE4808EB98 +:1080B000C10A006890F8471A8BF81810CB4950464F +:1080C0003839FFF789FF022806D0641C64B295F99D +:1080D0001006A042E0DA25E0C44A89F80060383A88 +:1080E000DAF82810C2F83A1089F80640B9F80810F2 +:1080F000491CA9F8081015E094F82431042B01D08C +:10810000062B0DD180461346A81C0BF0D7F801288A +:1081100006D1B64920463839FFF7C8FE012804D0F9 +:1081200085F800B03846BDE8F09F2889B8F80E20E1 +:10813000904233D30220287014F8602F8AF8002070 +:1081400062788AF80120A2788AF80220AA48E278A8 +:108150008AF80320067089F80160182289F8022045 +:1081600014F8362C89F8032034F8362C120A89F8D2 +:10817000042014F8382C89F8052034F8382C02E053 +:108180000FE05EE09AE09848120A89F8062000683D +:10819000012790F8500A88F81800C3E7401C28818E +:1081A000C0E794F82401042801D0062818D113460A +:1081B000A81C0BF083F8012806D18C4920463839D9 +:1081C000FFF774FE012813D094F82461082084F886 +:1081D00024012046FFF749FE0320287084F824611B +:1081E00094F8240108289DD12046FFF73EFE69E05F +:1081F00094F860108AF8001094F861108AF8011061 +:1082000094F862108AF802107B4894F863108AF898 +:108210000310067089F80160182189F8021094F89B +:108220002A1089F80310618D090A89F8041094F85E +:10823000281089F80510218D090A89F806100127F0 +:10824000CEE794F82401042801D0062836D113463D +:10825000A81C0BF033F8012830D164492046383986 +:10826000FFF724FE012829D194F860108AF8001045 +:1082700094F861108AF8011094F862108AF80210DC +:108280005D4894F863108AF80310067089F801605D +:10829000182189F8021094F82A1089F80310618DCA +:1082A0000127090A89F8041094F8281089F80510A4 +:1082B000218D090A89F806100220287094F82401FB +:1082C000082890D1FFF7BAFD2CE72DE9F05F0546AD +:1082D000494800260178DFF81491DFF80CB1A9F1C4 +:1082E0001C0939B1DBF8001091F8511A89F81810FF +:1082F00000210170DFF8F4A005F5805450469AF88B +:1083000000804FF0010CB8F1000F1FD086463748AF +:108310000127364A8079DFF8DCA08740C0EB0011E6 +:108320001C3A01EB401005EBC000927E00F12801E1 +:10833000B8F1010F3ED0F146B8F1020F7DD0B8F18F +:10834000030F7BD0B8F1040F79D006E10027CB46AC +:10835000E0461AE0D4F8081608FA07F0014212D0F5 +:10836000C7EB071000EB471005EBC0091E4800687B +:1083700090F8491A8BF818101C4948463839FFF70D +:108380002BFE022806D07F1C7FB294F91006B8425B +:10839000E0DAE5E0154A8AF80080383AD9F8281082 +:1083A000C2F83A108AF80670BAF80810491CAAF800 +:1083B0000810D5E0D4F808367546E0463B427DD03B +:1083C000044690F82401042801D0062819D1134648 +:1083D000A81C0AF073FF012811D1044920461C395A +:1083E000FFF764FD012809E0040710005028100081 +:1083F000C5061000E8271000C406100002D00420B3 +:108400002870ADE02889B9F80E10884221D30220E7 +:1084100028708AF8018018218AF8021014F82A1F9F +:108420008AF8031034F80219090A8AF8041021782E +:108430008AF805102188090A02E00DE053E085E082 +:108440008AF80610DBF8000090F8510A89F8180045 +:108450007AE0401C288183E0D4F80836E0463B42AD +:1084600001D128463CE0044690F82401042801D0BC +:10847000062830D1134609F102000AF01FFF012837 +:1084800005D171492046FFF711FD012804D099F864 +:108490000000022819D01EE08AF8018018218AF80D +:1084A000021094F82A108AF80310618D090A8AF8DC +:1084B000041094F828108AF8051000E04DE0218D92 +:1084C000090A8AF80610012605E02046FFF7CDFCD0 +:1084D000032089F8000094F82401082840D12046A0 +:1084E000FFF7C3FC36E0D4F8083665463B4231D08E +:1084F000044690F82401042801D0062830D1134600 +:1085000009F102000AF0DAFE012829D14E4920467D +:10851000FFF7CCFC012823D18AF8015018218AF8F2 +:10852000021014F82A1F8AF8031034F80219090AF5 +:108530008AF8041021788AF805102188090A8AF837 +:108540000610022089F80000012609E0D4F8080688 +:10855000384205D1FFF772FC02E004208EF80000DB +:108560003046E0E53849B0F92A201C39B1F902302B +:108570009A420FDBB0F92800B1F90030984209DBCC +:10858000B1F906309A4205DCB1F90410884201DCE9 +:10859000012070470020704710B52B4990F8243116 +:1085A00000221C395B1E052B14D8B0F92A30B1F912 +:1085B0000240A3420EDBB0F92800B1F90040A0420E +:1085C00008DBB1F90640A34204DCB1F9041088428B +:1085D00000DC0122104610BD30B51478844204D26C +:1085E0005578854201D90A2011E0844204D155789A +:1085F000854201D0187809E0844204D0547884423E +:1086000001D1987802E018789C786043C0B29478E1 +:108610008C4204D2D5788D4201D90A2111E08C42D6 +:1086200004D1D5788D4201D0197909E08C4204D06B +:10863000D2788A4201D1997902E019799A79514325 +:10864000C9B2484330BD000034281000FE48002164 +:1086500001808170FD480268FB480A3892F8A43B0B +:10866000437092F8922B82700170017170472DE96E +:10867000F041F64900F580534FF001050E684FF0C8 +:108680000E0196F893CA5FEA8C721AD5D3F80846A1 +:108690000A4600BF05FA02F73C4210D0C2EB0217AF +:1086A00007EB421700EBC70797F825717F0706D540 +:1086B000E54A96F8944A521F1470557001E0521E14 +:1086C000E8D25FEA4C7225D5E14AD279002A21D05E +:1086D000DD4C00220A3C2281D3F8083605FA01F766 +:1086E0003B420FD0C1EB011707EB411700EBC70767 +:1086F00097F825C15FEA4C7C04D0B7F842709742E6 +:1087000000D93A46491EE9D22281B6F9B90AFDF7E5 +:10871000BBFEE070BDE8F081CC49096891F8931A7E +:1087200089070AD5C849491F10B10020487003E0E5 +:108730000878002801D0401E087070472DE9F041EC +:108740000646C24800252C46006890F8931A4A074E +:1087500026D5BF4AD2791AB3BB4A90F8B73A0A3A3B +:1087600090F8BB1A1779012F08D190F8B8CA90F881 +:10877000BC0AA3EB0C03081ADBB2C1B21089984201 +:1087800002D8D078884203D9042086F82501012434 +:10879000214614718F4214D009200AF011F910E01B +:1087A000880707D5A848401F4178012908D00078DC +:1087B00030B906E0C80704D096F82501042800D196 +:1087C00001252543A6D0A349AA20087096F82401C4 +:1087D000032805D0042801D006289BD1082000E0FA +:1087E000022086F8240195E72DE9F04F974981464C +:1087F00000200C6809F58053934AB4F89DAB0146FC +:108800000A3A93F9106641E00127D3F808568F40E1 +:108810003D423AD0C1EB011505EB4117DFF838C2F4 +:1088200009EBC70797F861509CF800C0AB46ACF164 +:10883000020C654507DBB4F83280B7F922C0A8EB1B +:108840000A05AC452CDA97F83E506D071DD497F811 +:1088500060C094F8958BABEB0C0597F863C097F864 +:1088600062706D1CACEB0707EDB27F1C05EB850C4D +:10887000FFB24FEA4C0CBCFBF7FCA84505D2BD4249 +:1088800003D994F8965B65450AD3491C8E42BBDA3E +:1088900094F8921B917011F0FF0F05D0BDE8F08F96 +:1088A000917809B1491EF5E70120F7E72DE9F04776 +:1088B00066486A490025046809782A46B4F9A20B7B +:1088C000174684460B46664E07E000BF36F9138014 +:1088D000E04502DD521C474412B25B1EF6D24FF057 +:1088E000640A002A09DD97FBF2F294F8A53B12B264 +:1088F000534393FBFAF212B207E0624605E000BF71 +:1089000036F91130934200DD6D1C491EF8D294F8FF +:108910009F2B002184460E461346DFF8489194F8B9 +:10892000A07B07E039F91280E04502DD491C46448E +:1089300009B2521C9742F5DC002908DD96FBF1F0E4 +:1089400094F8A51B00B2414391FBFAF000B24946EE +:1089500006E000BF31F91320824200DD6D1C5B1C74 +:108960009F42F7DA384894F8A11B0A38A94203DA83 +:108970003D490978012902D094F8A41B02E041780E +:1089800039B1491E417011F0FF0F02D00020BDE83F +:10899000F0870120FBE7F0B52C4A00F580534FF03B +:1089A000010C1468002293F91066B4F8935B18E088 +:1089B000D3F808760CFA02FE17EA0E0F10D0C2EBBD +:1089C000021707EB421700EBC70749B1B4F832E0D2 +:1089D000B7F90270AEEB050E774501DA491EC9B250 +:1089E000521C9642E4DA94F8910B884201D201209D +:1089F000F0BD0020F0BD2DE9F041144D0746286878 +:108A000090F88B0B01064CD518490978002948D0FD +:108A10000D4C00074FF0010603D5FFF747FF012873 +:108A200010D041F20860042138440FF055F9C1B26A +:108A3000286890F88B0BC0071FD0F1B13846FFF7BC +:108A4000AAFFD0B1286813E07A05100004071000CF +:108A5000A85110009206100086061000850610002E +:108A6000A80A0120D20A0120FC04100046071000C9 +:108A700090F88C0B2070A67009E0286890F88B0B9A +:108A8000800704D53846FFF7AFFE0028DAD16078BA +:108A9000002806D1A078012803D1AA2009F08CFF74 +:108AA000667037E62DE9F0474F4E044600253068E2 +:108AB00090F88B1B09063AD54C49097881B34C498B +:108AC0008978012933D1B0F8987B41F208600421FC +:108AD00020440FF001F904F58051C2B200204FF09C +:108AE0000109366891F910361FE0D2B1D1F8088635 +:108AF00009FA00FC18EA0C0F16D0C0EB001505EBC4 +:108B0000401504EBC505B6F83280B5F902C0A8EBF4 +:108B10000708C44507DB95F83E506D0703D40025D0 +:108B200005E0012503E00125401C8342DDDA2846EB +:108B30002DE770B52C4E316891F88B1B090625D5B1 +:108B40002A490978002921D0294C002510B1A570A7 +:108B5000257006E0207820B1401E10F0FF00207044 +:108B600000D1A5706078012810D1A07800280DD11F +:108B7000BB2009F021FF657031681D480A3891F863 +:108B8000A42B427091F8921B8170057070BD16493C +:108B9000096891F88B1B09061FD51449097800292B +:108BA0001BD013498A78012A02D00978002914D0F1 +:108BB0000F490A39097800290FD00E4ABB211170DC +:108BC00090F82411032905D0042901D0062904D1E5 +:108BD000082100E0022180F8241170470449012097 +:108BE0000A3908707047000004071000460710009B +:108BF0007A0510009206100090F8611090F860203D +:108C00008A1AC18F521C022A0ED990F8632090F85C +:108C100062309A4208D148F20402114204D141F074 +:108C20000101C1870120704721F00101C1870020A7 +:108C3000704770B50446002084F82801F848F94DC3 +:108C40000E460178286811B9F749097831B194F9CD +:108C5000321190F86302B1421ED028E094F8251139 +:108C600001290BD010F080FC002894F9320135D096 +:108C7000B042286890F89B0319D10DE0EB490978C0 +:108C800069B110F071FC002894F932010AD0B042A9 +:108C9000286890F84D030AD100F00F0008E090F822 +:108CA0004B03F9E7B042286890F84C03F4D0000970 +:108CB00084F828012046FFF79FFF01280DD1DC48EA +:108CC0000078012809D9296894F8280191F89C13A3 +:108CD00001F00F01084484F8280170BDB04203D1AF +:108CE000286890F89A03D7E794F83C00C0062868F3 +:108CF00002D590F89C03DAE790F89A03D7E7CB49BE +:108D000010B50C78C74990F82821096891F89A3372 +:108D100003F00F0364B191F84C1300BF01F00F0191 +:108D2000C91A511A002900DC002180F8281110BD51 +:108D300091F84B13F2E72DE9FC47BA4D0446286839 +:108D400090F87F03C00749D02146201D0AF005FB9B +:108D50008046214604F120000AF0FFFA814610F017 +:108D600003FC0028286805D0B0F89363B0F88F732F +:108D7000764304E0B0F89163B0F88D7376432968C8 +:108D8000E06A7F4391F8DA13884216D3B04514DCC9 +:108D9000B4F8CC00ADF80200B4F8C800ADF800009B +:108DA000B4F8D400ADF80600B4F8D000ADF8040073 +:108DB00001A968460AF0D1FA80462A68E06A92F86A +:108DC000DA1388420CD2B9450ADD92F8DB0340433E +:108DD000814509DC204600F0FFF928B9BDE8FC8791 +:108DE0008842FBD3B045F9DDE08F40F00200E08718 +:108DF000F4E79049002008708D4908708B4908708D +:108E00008D4908808D49087070472DE9F04F8BB06F +:108E1000002500F5805604468DF810508DF814504A +:108E2000B6F80806834F0004000C10D02046FFF768 +:108E30001EFC2046FFF7DFFD4FF0FF39387849462A +:108E40004FF00048BB464FF0010A60BB12E0784883 +:108E50003D7005702046FFF7CEFD0020FFF769FE4C +:108E60000120FFF759FC74480580744805700BB069 +:108E7000BDE8F08F04F58052002092F9107621E0D1 +:108E8000D2F808C60AFA00F31CEA030F18D0C0EBA8 +:108E9000001303EB401304EBC30393F824C1BCF1AC +:108EA000010F01D049460FE0B3F840C0BCF1000FFC +:108EB00006D01B6B93FBFCF3984501DA98460146FC +:108EC000401C40B28742DBDA0091A8468BF8005084 +:108ED0000027DFF85091E2E0D6F808160AFA07F00A +:108EE00001426DD0C7EB071000EB471004EBC00543 +:108EF00095F82401012806D005280CD0092820D097 +:108F00000D282DD010E028460099FFF792FE022090 +:108F100085F8240133E0284600F0E0F8062085F8C3 +:108F200024012846FFF707FF95F82401022826D0E0 +:108F3000062846D007284FD00A280DD00E281AD070 +:108F400058E0D9F8000090F89E0300F00F0085F873 +:108F500028010A2085F8240195F8280178B349E012 +:108F6000D9F8000090F8A10300F00F0085F829015E +:108F70000E2085F8240195F82901F0B13AE095F822 +:108F80003E00C00713D02846FFF736FE78B9D9F85F +:108F9000001095F8280191F89C1301F00F01884208 +:108FA00003D9401A85F8280101E085F82881E88F67 +:108FB00040041FD495F82801DFE7032018E016E0ED +:108FC00065E095F82901A8B995F83E00800701D51C +:108FD00007200DE008200BE0D9F8000090F87E0390 +:108FE0008006F7D595F8A000012803D0F2E70B2002 +:108FF00085F824012846FFF7A1FB2846FFF7C7FDA7 +:1090000095F8240102281BD0062824D00A2829D04C +:109010000E2820D0032829D0042827D03DE00000C6 +:1090200038051000040710004205100091061000DA +:10903000B9061000920610007805100073051000A4 +:10904000E88F400429D400BF95F82801F8B1401EEC +:1090500085F8280121E095F82901C0B1401E85F866 +:1090600029011AE02846FFF766FEEDE79BF80000AD +:10907000401C8BF8000095F82501012802D0032838 +:1090800006D00AE09DF81400401C8DF8140004E09E +:109090009DF81000401C8DF810007F1C7FB296F9DF +:1090A0001006B842BFF618AF05AA04A9204600F082 +:1090B00059F80020FFF730FB62499DF81000087056 +:1090C00061489DF8141001702046FFF7EBFC002862 +:1090D0003FF4CDAE0020FFF72CFDC8E670B50026AA +:1090E000044680F829615948594D0178286811B122 +:1090F00090F8640216E0574909780029F8D110F079 +:1091000033FA60B12868012690F89F035FEA1010D7 +:1091100084F8290194F82501012806D00EE028687A +:1091200090F89F0300F00F00F2E7296894F82901F6 +:1091300091F84B1300EB111084F829011EB994F833 +:109140003E0080070DD42868E16A90F8A00300F083 +:109150000F02914205D994F8291101EB101084F8FF +:10916000290170BDF0B50C7813783B4F012534B15F +:109170007BB3002300F580544FF0020C22E0002B5B +:1091800029D03D7022E000BFD4F8086605FA03FE3E +:1091900016EA0E0F14D0C3EB031606EB431600EBD2 +:1091A000C60696F824E1BEF1030F09D196F825E131 +:1091B000BEF1010F04D186F824C11678761E167010 +:1091C0005B1C5BB294F910669E42DDDA08780028D9 +:1091D00001D000203870F0BD30B5C18F01230905E2 +:1091E00001D5012030BD1A4CB0F95A20B0F9581001 +:1091F000246802FB01F5002D0CDA002A00DA524245 +:1092000094F8DC53AA4205DD002900DA4942A9425C +:1092100000DD0023B0F95E10B0F95C0001FB00F244 +:10922000002A0CDA002900DA494294F8DC23914242 +:1092300005DD002800DA4042904200DD0023184698 +:1092400030BD000093061000940610003805100091 +:109250000407100042051000910610002DE9F843A4 +:109260000746FF48894616460178FE480078FE4CBE +:1092700001B990B1206890F8C013B0F8CB2301F089 +:109280000F030D09B0F8C9134943524348460095EE +:109290000AF071F83560BDE8F88310F065F958B14F +:1092A000206890F8B613B0F8B92301F00F030D0948 +:1092B000B0F8B7134943E8E797F82501022818D01A +:1092C000012822D0246894F8E10394F8E0C300F068 +:1092D0000F030509E548017831B194F8E72394F8C4 +:1092E000E6C302F00F03150997F82321012A18D0CD +:1092F0002EE0206890F8BC13B0F8C32301F00F03F0 +:109300000D09B0F8C1134943BFE7206890F8BD13B9 +:10931000B0F8C72301F00F030D09B0F8C513494396 +:10932000B3E794F8998AFA6A424511D294F89A1AE6 +:1093300094F8BB03B2FBF1F194F8982A00F00F0304 +:1093400002F00F02551AB5EB101F1CDA05091AE0DE +:10935000B7F84020624505D9B4F8E213B4F8E42325 +:10936000494392E794F8BB2302F00F03150909B1B2 +:109370000379457997F83C00C00604D594F8DD03DD +:1093800000F00F03E2E7B4F8C113B4F8C323494374 +:109390007BE72DE9F843884690F82411044600F154 +:1093A000940703290DD0B04D042928680FD0072950 +:1093B00042D008293FD141463846BDE8F84300F085 +:1093C000B3BB41463846BDE8F84300F070BB90F8A7 +:1093D000BE0304F10C010609081D09F0BEFF014699 +:1093E0006A462046FFF73AFF034694F82301012816 +:1093F00010D12868E16A90F8992A91420AD290F82F +:109400009A2A90F8BE03B1FBF2F6B6EB101F05DD09 +:10941000060903E09548017801B1867954F89C1F4C +:109420003246184609F0BCFF05460246414638461A +:1094300000F042FB25602EE790F87F1300268A0794 +:10944000314602D594F8A02042B184F8A0103246EB +:1094500041463846BDE8F84300F046BB90F8BF03EC +:1094600000F00F0610F080F818B1286890F8BF03DC +:109470000609012084F8A000E9E72DE9F04104463F +:1094800000F1A805C08F0F4600054FF0050603D573 +:1094900094F8180101281ED0702128460FF02AFFE9 +:1094A00005EBC60178684860386845F83600761ED6 +:1094B000F6D200BFD7E90001C5E90D0101202863FC +:1094C00005F1580305F1400205F134012846BDE8D5 +:1094D000F04109F0F1BF182105F140000FF00AFF3B +:1094E000182105F158000FF005FF94F81A01012822 +:1094F0001FD194F82201012802D003280DD018E0D2 +:1095000094F8230110B9E089A4F82001B4F82001EF +:109510006084B4F81E0120840BE094F8230110B994 +:10952000A089A4F81E01B4F81E012084B4F820011B +:10953000608494F8230101283AD0B4F920117868A6 +:10954000E962401A90FBF6F0B4F9201100EB4002FA +:1095500001446962B4F9201101EB4001E961B4F9F9 +:10956000201111446961B4F9201101EB8000E86019 +:1095700078686860B4F91E113868A962401A90FBD7 +:10958000F6F0B4F91E1100EB400201442962B4F96F +:109590001E1101EB4001A961B4F91E1111442961AA +:1095A000B4F91E1101EB8000A8603868286081E7DB +:1095B0005FF0000005EBC002B4F920115160B4F96E +:1095C0001E1145F83010401CC0B20628F2D371E7D6 +:1095D00010B50446D1E90002C4E90D020622204676 +:1095E00009F0A1FE206B04F15803401C206304F134 +:1095F000400204F134012046BDE8104009F05CBF90 +:10960000D1E90021C0E93721D0F8D8100023491C46 +:10961000C0F8D81000F5807200F1E801DC300AF0E3 +:109620005EB82DE9FC47DFF848800C460968C8F8A9 +:109630000010DFF8349021680546C8F80410D9F806 +:10964000000017464FF0010A90F87F03400631D51D +:10965000B4F90200019005F1A806B4F9000009E090 +:10966000380510004205100004071000D006100055 +:109670007E051000009095F82401032808D00428E6 +:109680000BD0062809D007280CD008280AD00DE0F6 +:1096900069462846FFF7F1FE08E069463046FFF7C5 +:1096A00097FF03E069462846FFF7AAFF308F6080E6 +:1096B000B08E20802168C8F808102168C8F80C1006 +:1096C000D9F800004E46B0F93210B4F9020009F0A2 +:1096D0000CFE60803068B0F93410B4F9000009F075 +:1096E00004FE208095F82401032806D0042808D021 +:1096F000072817D0082815D017E03988A5F84E108C +:1097000013E03068B5F84E2090F8BE0300F00F006B +:10971000C0F110014243388800FB01200009A5F880 +:109720004E0001E0B5F84E003880D74A214605F1D9 +:10973000240000F0A0F95046BDE8FC872DE9F34F66 +:10974000D24883B000250560CF48DFF844932E4609 +:10975000056089F80050039FDFF838B34FF0010A25 +:1097600007F58057ACE000BFD7F808160AFA06F0F4 +:1097700001426ED0C6EB061000EB4611039800EBD9 +:10978000C10484F8705194F8240103280BD00428F4 +:1097900009D0072807D0082805D0092803D00A28AF +:1097A00001D00B2855D1E0680090B4F84C00ADF81A +:1097B000040004F10C01B54A081D00F05CF901AA8F +:1097C00069462046FFF72DFF8046DBF8000090F841 +:1097D0007E03400604D56946204601F08DF9804697 +:1097E000DBF8000090F87E03800603D5694620462A +:1097F000FFF7CFFDDBF8000090F87F0340070CD5A2 +:10980000B8F1000F09D094F82401032805D1608C29 +:10981000ADF80200208CADF8000094F82501012875 +:1098200008D19D48007828B994F82401082801D06F +:109830004FF000089948007828B39948007801282B +:1098400008D094F83E00400715D500BF4FF000083F +:1098500019E034E004F12000029001F0D5FA18B9C3 +:10986000029801F0E0FA08B14FF0000894F83E00C9 +:109870004007EBD407E094F81801012803D1206ACF +:10988000009084F8185194F8250103280CD199F818 +:109890000000401CC0B289F8000094F83E20520736 +:1098A00002D5401E89F8000000986062BDF80400EF +:1098B000A4F84E00B8F1010F16D084F87051761C50 +:1098C00097F91006B042BFF64FAFDBF8000090F8F2 +:1098D0003804000720D599F800107248B9B17249D0 +:1098E0000978012911D012E00098A061BDF80400A8 +:1098F000A4F85000049894F8322101680AFA02F2A0 +:109900001143016084F870A1D9E780F800A0D7F86E +:109910000C16002900D1057005B0BDE8F08F2DE9C7 +:10992000F0478946064600274FF0010800F58055AC +:1099300043E000BFD5F8080608FA07F210423BD012 +:10994000C7EB071000EB471006EBC00494F82401A6 +:1099500003280BD0042809D0072807D0082805D0F1 +:10996000092803D00A2801D00B2825D194F83231D8 +:10997000D9F8002008FA03F10A421DD0032803D1C8 +:109980002146304602F0C0FA94F93301002813DB77 +:1099900094F825010021012804D0022804D00428CD +:1099A00004D004E0032102E0042100E0052184F852 +:1099B0002611204608F0F5FF7F1C95F91006B842E5 +:1099C000B8DA00273DE000BFD5F8081608FA07F21C +:1099D000114235D0C7EB071101EB471106EBC1046B +:1099E00094F82411082902D00B2915D028E094F806 +:1099F0003221D9F8001008FA02F0014207D094F998 +:109A00003301002803DB2146304602F098FA214654 +:109A1000304602F05BFA13E094F83221D9F80010D6 +:109A200008FA02F001420BD094F93301002807DB59 +:109A3000E08F214620F40060E087304602F07FFA94 +:109A40007F1C95F91006B842BEDABDE8F0870F49D1 +:109A5000002008600C49086000F028B838B50446BA +:109A60000020009069462046FFF768FE69462046C0 +:109A7000FFF755FF38BD10B5144609F06EFC21689C +:109A8000814200DA206010BDC0061000BC06100044 +:109A9000B9061000040710009106100047071000D7 +:109AA0004C071000450610004406100070470022C5 +:109AB0008260027300F03DB87CB5044615460E4640 +:109AC000684600F036F801992A46606800F043F8CD +:109AD000606000992A46206800F03DF82060214629 +:109AE000304600F02FF87CBD7FB5044640680190F9 +:109AF0002068009015460E4602A800F01AF8039858 +:109B00006060029820602A460399019800F023F8CB +:109B100001902A460299009800F01DF800906946CD +:109B2000304600F00FF87FBD0A460146104600F0AF +:109B300009B8B1F9022012024260B1F9001009021D +:109B4000016070474A688032121242800968803191 +:109B5000091201807047C2F11003504301FB03005A +:109B600000117047B0F84020B1F840301A44A0F816 +:109B70004020B0F84220B1F842301A44A0F8422008 +:109B8000026B0B6B1A440263426B4B6B1A444263C9 +:109B9000B1F95220B0F952309A4201DDA0F85220BA +:109BA000B1F95420B0F954309A4201DDA0F85420A4 +:109BB00090F82C2191F82C319A420AD030F8462F97 +:109BC000B1F846301A4420F80E29896B0268114416 +:109BD000016070472DE9F04F97B0804600F5805046 +:109BE00000261190BEE00020089005901090129081 +:109BF000814682468346054607460A900B900C90A4 +:109C00000D9008EB860000F580501490D0F8840683 +:109C10000AAA044617E000BF90F82C1108EB010CCB +:109C2000535C0CF5805C5B1CDBB253549CF872C631 +:109C3000634506D1012B04D901238B4012990B43B4 +:109C40001293D0F86C010028E6D140E094F82C1172 +:109C5000012000FA01FC12991CEA010F12D1606B7D +:109C6000B4F90E30059A4946C0FB031205928946A5 +:109C7000B4F90C3051465A46C0FB03128A4693464B +:109C8000054419E008991CEA010F15D1A06BB4F93D +:109C90001E30059A4946C0FB031205928946B4F965 +:109CA0001C3051465A46C0FB03128A4608990544A7 +:109CB0004CEA010093460890204600F00EFC012873 +:109CC00002D11098401C1090D4F86C417F1C002CDD +:109CD000BCD1002F44DDE817044603462A46484617 +:109CE00005990FF042FAADF81E002A462346504669 +:109CF00059460FF03AFAADF81C0014984FF0FF37B0 +:109D00000025D0F8844623E0204600F0E6FB012839 +:109D100001D0109890B904F1100107A809F01DFBBB +:109D2000B8420BD207463DB129462046FFF71AFF3D +:109D30002946404600F0E8FB254607E02146284634 +:109D4000FFF710FF2146404600F0DEFBD4F86C41DF +:109D5000002CD9D10798E860E88F40F04000E887F0 +:109D60001198761C90F8FC06B0423FF73CAF17B054 +:109D7000BDE8F08F2DE9F74F05460E46C1EB061002 +:109D800000EB461082B005EBC00A00244FF001083A +:109D9000DFF894B505F580577FE0D7F8081608FA84 +:109DA00004F9424611EA090F76D0B44274D0DBF8C8 +:109DB0000C00904630F8160010EA090F6CD1C4EB85 +:109DC000041000EB441005EBC000009000F07FFB96 +:109DD000012804D0009800F080FB01285CD1009895 +:109DE00000F06DFBF0BB00990AF10C000C3109F09A +:109DF000B4FA0190DBF80C0008FA06F230F81630DD +:109E000043EA090320F8163030F81430134320F8E1 +:109E100014305046DBF8049000F06BFB012804D1AD +:109E2000009800F054FB01281BD0504600F04FFB77 +:109E3000012804D1009800F05CFB012811D05046A5 +:109E400000F045FB01281CD1009800F040FB0128E0 +:109E500017D100999AF83E0091F83E100843800609 +:109E60000FD500E018E0BAF83E00DBF8089040F0AB +:109E70002001AAF83E100098C08F40F02001009801 +:109E8000C1870198484507D241F284605146284471 +:109E9000049B009A00F047FB641C97F91006A0424F +:109EA000BFF67BAF05B063E72DE9F84F884606465D +:109EB000C1EB011101EB481006EBC004DFF868A408 +:109EC00094F83E004FF0040B40064FF0010906F5F0 +:109ED00080552DD5002704F10C0B23E0D5F808168A +:109EE00009FA07F001421CD047451AD0C7EB07100A +:109EF00000EB471006EBC000009000F0E8FA0128E4 +:109F00000FD1009800F0DBFA58B90099584610318B +:109F100009F023FADAF80810884202D2042084F803 +:109F200024017F1C95F91006B842D7DABDE8F88FF6 +:109F3000FE49E06A096891F895138842F6D900272E +:109F40002FE000BFD5F8081609FA07F0014227D024 +:109F5000474525D0C7EB071000EB471006EBC000C4 +:109F6000009000F0B4FA01281AD1009894F82C114E +:109F700090F82D01814213D1009800F0A0FA78B931 +:109F8000009904F10C00103109F0E7F9DAF8081033 +:109F9000884205D284F824B1E08F40F04000E08789 +:109FA0007F1C95F91006B842CCDA002728E000BFE4 +:109FB000D5F8081609FA07F0014220D047451ED00F +:109FC000C7EB071000EB471006EBC000834600F01C +:109FD00084FA012813D1584600F071FA78B90BF1D0 +:109FE000100104F10C0009F0B8F9DAF80810884201 +:109FF00005D2BBF83E0040F04001ABF83E107F1C9C +:10A0000095F91006B842D3DA90E72DE9F8430646F1 +:10A01000FF2000258DF80000012706F5805419E087 +:10A02000C5EB051000EB451006EBC008D4F8080698 +:10A0300007FA05F108420CD0404600F040FA01282A +:10A0400007D098F82401052803D129463046FFF7A8 +:10A050002BFF6D1C94F91006A842E1DA00251BE0E5 +:10A06000C5EB051000EB451006EBC008D4F8080658 +:10A0700007FA05F108420ED0404600F020FA012808 +:10A0800009D0404600F029FA012804D16A46294641 +:10A090003046FFF76FFE6D1C94F91006A842DFDA18 +:10A0A0000025B84620E000BFC5EB051000EB4510C9 +:10A0B00006EBC007D4F8081608FA05F0014212D0E2 +:10A0C000384600F0FCF901280DD0384600F0FFF9C1 +:10A0D000012804D16A4629463046FFF74BFEF88F27 +:10A0E00020F02000F8876D1C94F91006A842DBDAF6 +:10A0F0009DF80000401C84F8FC06BDE8F88310B50C +:10A100000446894803210C3006F0A4FB86481E2132 +:10A11000C0680FF0CDF841F284607C2120440FF03C +:10A12000E9F8824802688248B2F896138079494378 +:10A1300010B1B2F86A1349437E480068C00106D5E1 +:10A140007D480078062802D1B2F8DE134943B2F800 +:10A15000982302FB0210744A121D1160111D086041 +:10A160002046FFF752FF2046FFF734FD6E480321DB +:10A17000BDE810400C3006F085BB2DE9F0470446E1 +:10A1800091425CD007D901EB0200A0EB0201CAB2F8 +:10A19000A0EB0200C1B2C1EBC10000EB400004EB38 +:10A1A0008001C2EBC20000EB400004EB8000B1F97B +:10A1B0003250B0F9323081469D4200DA4B86CB8C6A +:10A1C000C58C2B44CB840B8D058D2B440B858B6963 +:10A1D00085692B448B61C769CE69CB68D9F80C00BF +:10A1E0004FEA234C4FEA20480CFB06FCF51907FB0D +:10A1F00008CC9CFBF5FC6CF31F430FFA83FC0CFBB3 +:10A2000006FC00B207FB00C090FBF5F060F30F0303 +:10A21000CD61CB6094F8EC04411E91420AD0C0EBB2 +:10A22000C00000EB400004EB800148465422543942 +:10A230000FF004F894F8EC04401E84F8EC04BDE838 +:10A24000F0872DE9FE4F16460F468346012B2FD18E +:10A2500001203A4A10E000BF17F8101011B1491E52 +:10A2600007F8101007EB400314785978641EA142D8 +:10A2700001DA491C5970401C97F82C108142EBD22E +:10A2800001202F4A10E000BF16F8101011B1491E2E +:10A2900006F8101006EB400113784C785B1E9C42C8 +:10A2A00001DA641C4C70401C96F82C108142EBD2F1 +:10A2B0001E484FF00109CA460068B0F88E024043BC +:10A2C0000290002001908CE0012082E000200090AC +:10A2D0009BF8EC043FE000BFC0EBC00101EB410282 +:10A2E0000BEB820202F1440116F818400B78A342EE +:10A2F00031D306EB48046478A3422CD8497817F888 +:10A300001930994227D307EB49035B78994222D849 +:10A310000C49097839B10C49097821B192F8241017 +:10A3200011F0060F17D111E090051000040710007E +:10A33000A851100060051000E80410008506100008 +:10A34000860610004406100046061000009A0AFA1D +:10A3500000F111430091401EBED2042168460DF069 +:10A36000BBFC012833DD00245246009901E0641C47 +:10A37000E4B202FA04F092460842F8D09BF8EC549A +:10A3800022E000BF00990AFA05F008421CD0C4EB95 +:10A39000C40000EB40010BEB8100C5EBC50101EBF4 +:10A3A00041010BEB81010C300C3108F0D6FF029912 +:10A3B000884209D2EAB221465846FFF7DEFE7049CC +:10A3C0000120019081F800A06D1EA542DAD808F1A5 +:10A3D000010096F82C1080464145BFF477AF09F193 +:10A3E000010997F82C104945BFF46EAF0198BDE8FC +:10A3F000FE8F644810B540780C46002856D062485D +:10A400000078002852D16148007800284ED1604879 +:10A4100094F8EC24006890F889128A4246D8002308 +:10A420000BE000BFC2EBC20101EB410104EB810173 +:10A43000B1F93210994200DD0B46521EF2D2554955 +:10A440000B80B0F88A12994230DBB0F98C120022EE +:10A450005148FBF7B0FB5049D1E90002104325D029 +:10A46000D1E90201084321D04B4A0123A2F158014E +:10A47000A1F15800FBF7BFF84748B03890F82C100E +:10A48000002913D0583090F82C0000280ED04143FA +:10A4900094F8EC040023814200D201233E4A204676 +:10A4A000583ABDE81040A2F15801CAE610BD39493A +:10A4B0000020C86038480F2110300EF01BBF90F804 +:10A4C0003E00400701D5012070470020704790F8FA +:10A4D0002401012800D00020704790F824010228B0 +:10A4E00005D0032803D0042801D0002070470120A4 +:10A4F000704710B590F83E10490603D5FFF7EDFF01 +:10A50000012800D0002010BD91F82421012A08D094 +:10A51000022A06D0062081F82401002081F82901B2 +:10A52000704701F0D3BCF0B591F9316193F9004067 +:10A5300092F93151771C02D06D1C15D00BE06E1CC6 +:10A540000BD000EB850200EB8400D26BC2F86C11DB +:10A55000C16381F831411C70F0BD641C64B240F8E5 +:10A56000241081F8314102E000EB8601C96B00EB59 +:10A570008400C1F86C21C26382F83141EBE700002E +:10A58000A8051000A8511000380510004205100061 +:10A590000407100090051000102910002DE9F0416B +:10A5A000044690F89200FF4E00270D467F284FD1B9 +:10A5B00004F10C01081D08F0D0FE0146204600F011 +:10A5C00021FB40B284F892000F2802DD0F2084F8AE +:10A5D0009200E08F80053BD56888B4F97AC0B4F961 +:10A5E0007830A0EB0C0001B22888A26FE266D6F8A2 +:10A5F00000E0C01A64229EF8C7E900290EFB01FEA4 +:10A600009EFBF2F100B201DD614401E0ACEB01011F +:10A61000A4F872103168002891F8C71901FB00F105 +:10A6200091FBF2F001DD184400E0181AA4F8700064 +:10A630006888B4F87210401AA4F876002888B4F834 +:10A640007010401AA4F87400306890F8C709E8B395 +:10A6500094F99200B5F90220C0F110015143B4F908 +:10A660007A2000FB021040F30F106880E18F89050B +:10A6700010D5B4F96E10884203DDB4F9722090420F +:10A6800005DC884206DAB4F97210884202DAB4F8BE +:10A690007200688094F99200B5F90020C0F11001B1 +:10A6A0005143B4F9782000FB021040F30F102880CA +:10A6B000E18F890523D5B4F96C10884203DDB4F924 +:10A6C0007020904207DC88420BDA00E02AE0B4F9FF +:10A6D0007010884205DAB4F870002880E08F800599 +:10A6E0000DD5B5F90000B4F97010884207D1B5F95D +:10A6F0000200B4F97210884201D184F89270316876 +:10A7000094F8920091F8C91901F00F01401A40B273 +:10A7100084F89200002801DA84F892702868A06713 +:10A72000BDE8F08184F89270012084F89000F7E78A +:10A730002DE9F04188460546012790F892103846E9 +:10A7400071B195F8901001290AD00322414605F114 +:10A750007C0008F0D2FD95F89100012803D04EE06E +:10A7600085F89000DCE70EF0FFFE8E4E0028306882 +:10A7700006D090F8CC1990F8CD0961F31F440DE094 +:10A7800090F8CA1990F8CB0961F31F4460F30F04E5 +:10A790008548017821B1C07860F31F4460F30F044D +:10A7A00023145B4322B202FB023405F178004146D8 +:10A7B00008F0D3FD0023A0421BDC3168EA8F91F83A +:10A7C000C50900EB80004000120504D591F8C409CA +:10A7D00000EB8000400010B1EA6A824209D891F88B +:10A7E0007E03000600D40027A86FC8F80000384692 +:10A7F00096E785F8913095F992000028F7DD4146FB +:10A800002846FFF7CBFEF2E72DE9F84F044601207A +:10A810000D464FF0000B00900EF0A6FEDFF884A16D +:10A820000028DAF8000011D090F8D66990F8D779AE +:10A830000322294604F17C0008F05FFDE08F00054B +:10A840001DD594F81A01012805D018E090F8D469B4 +:10A8500090F8D579ECE7DAF80000E16A90F8DC09C5 +:10A8600081420CD26888B4F87A10401AB4F88C107F +:10A870000844A4F88C002888B4F878100BE06888A5 +:10A88000B4F88210401AB4F88C100844A4F88C0074 +:10A890002888B4F88010401AB4F88E100844A4F840 +:10A8A0008E00B4F98C00002801DB014600E0414233 +:10A8B000B1425EDD4FF0010B002801DD811B00E09D +:10A8C00081190FFA81F9A0EB0900A4F88C0034F883 +:10A8D0007A1F01EB090000B22080DAF80010B1F90C +:10A8E000321008F002FD24F87A09B5F90210864604 +:10A8F000081A02B2002A01DB104600E05042B042C2 +:10A900004EDDB4F98200081A00D54042DAF8008022 +:10A910000FFA80FC98F8DA3998F8DB6998F8D809CA +:10A9200098F8D9199C450FDB9E420DD0B44501DD46 +:10A93000084609E0ACEB030C091A0CFB01FCF11A08 +:10A940009CFBF1F1084400B2B4F98C10514300298A +:10A9500006DDB9F1000F00DC40427044A4F87A0033 +:10A96000B8F93210B4F97A0008F0BFFCA4F87A0004 +:10A9700016E0DAF80010B4F97E00498E884203D15F +:10A98000B4F982208A4203D050B9B4F8821039B9A0 +:10A99000B4F97A10814203D0A4F87A004FF0010B89 +:10A9A00004E0000004071000D0061000B4F98E0087 +:10A9B000002801DB014600E04142B94256DD002893 +:10A9C00001DDC11B00E0C1190EB2801BA4F88E008E +:10A9D00034F8780F304400B22080DAF80010B1F972 +:10A9E000341008F082FC24F87809B5F9001081468B +:10A9F000081A02B2002A01DB104600E05042B842B9 +:10AA000053DDB4F98000081A00D54042DAF800801E +:10AA10000FFA80FC98F8DA3998F8DB7998F8D809B9 +:10AA200098F8D9199C450FDB9F420DD0BC4501DD3C +:10AA3000084609E0ACEB030C091A0CFB01FCF91AFF +:10AA40009CFBF1F1084400B2B4F98E105143002987 +:10AA500005DD002E00DC40424844A4F87800B8F937 +:10AA60003410B4F9780008F040FC12E0DAF8002065 +:10AA7000B4F97C00918E884203D1B4F980308B42C6 +:10AA800003D048B9B4F8801031B9B4F978108142D4 +:10AA900002D0A4F8780008E0BBF1000F05D192F8CD +:10AAA0007E03000601D400200090A06F286000986B +:10AAB000BDE8F88F10B5044690F8240104281AD197 +:10AAC000E08F400517D404F10C01081D08F045FC87 +:10AAD00001466348006890F8C629E08F5243430559 +:10AAE00009D4914202DA40F4007003E020F40070CF +:10AAF00040F48060E08710BD2DE9F0410E46044629 +:10AB00000125FFF7D7FF94F82401032804D0042877 +:10AB100007D0082825D027E03146204600F029F844 +:10AB200022E04F4F386890F87F03C00609D53146C0 +:10AB30002046FFF7FDFD054694F89000012803D05C +:10AB40000CE0012084F89000386890F87F0300073B +:10AB500004D531462046FFF757FE0546012D03D0A8 +:10AB600005E0D4F8880030603068C4F888002846D2 +:10AB7000D6E570B504460868A0670D46032204F1C7 +:10AB80007C0008F0C7FB3648026892F87F03C106D4 +:10AB90004FF000002ED533490E7801217F231EB3DC +:10ABA000E68F360520D594F82361012E15D084F860 +:10ABB000900084F8911084F89230D4F81E11A167A7 +:10ABC0006988B4F87A30C91AA4F876102988B4F8DC +:10ABD0007830C91AA4F874100CE084F8901084F846 +:10ABE000910084F8920005E084F8900084F89110B8 +:10ABF00084F8923092F87F13090702D524F88C0F5D +:10AC0000608070BD10B50C460EF0AEFC14490A68A9 +:10AC100080B192F8D30992F8D03900F00F01000901 +:10AC200092F8D1295B4352439C4202DD94420CDBF3 +:10AC3000084610BD92F8D20992F8CE3900F00F0103 +:10AC400000095B4392F8CF29EDE79A4200D1521CEC +:10AC5000E41A411A4C43D11A94FBF1F1401A10BD89 +:10AC60000407100047071000F0B5F64A00261768E1 +:10AC70007B8E97F8954ABA8E97F836701D465FEA34 +:10AC8000477C03D5A3EB204C6CF31F405FEA877C25 +:10AC900003D5A2EB000C6CF30F00FF0706D00314E2 +:10ACA00060F31F4063F30F0013462A46DFF898C392 +:10ACB0009CF80050C5B10514B5EB530F05B206DA88 +:10ACC000B5EB520F01DA002507E0012505E0B5EBF1 +:10ACD000520F01DA022500E003250127AF400F42A1 +:10ACE00002D00CEB0501CC780114A14202DB1B1B46 +:10ACF0008B4206DA00B2A04202DB111B814200DA6D +:10AD000001263046F0BDD0490022897809B1C068DB +:10AD1000AAE7104670472DE9F041CB4F0D463A4661 +:10AD20000646797892F803C013790020C54C527911 +:10AD30005FEA017E06D01946604608F077FA0146C0 +:10AD4000B87916E08F0702D01946604611E0BE4F71 +:10AD500011F00B0FBF7901D0394603E011F0050F58 +:10AD600002D06146104604E011F00A0F10D03946B7 +:10AD7000184608F066FA58B1216891F8A42A824270 +:10AD800006D391F89E0A3070206890F89F0A0EE072 +:10AD9000216891F8A42A82420CD291F8A52A824215 +:10ADA00008D391F8A00A3070206890F8A10A2870A2 +:10ADB000BDE8F08191F8A52A8242F9D291F8A62A3D +:10ADC0008242F5D391F8A20A3070206890F8A30A65 +:10ADD000EDE730B50124039D9C4035B10914914243 +:10ADE0000EDA81682143816030BD09B2914203DAF5 +:10ADF00001682143016030BD41682143416030BD9D +:10AE0000C1682143C16030BD9049B0F90000B1F97B +:10AE10002020824203DCB1F92210814201DA0120B4 +:10AE20007047002070478949B0F90200B1F91A1043 +:10AE3000884201DD01207047002070472DE9F8436A +:10AE400091460646DDE9087208790025DDF828C03C +:10AE50000C46032832D27B48DFF8F481016891F870 +:10AE60004214E170D8F80480B8F1000F06DDD0F884 +:10AE7000008098F84384A1EB0801E1700068316B11 +:10AE8000B0F84404814217DDDBB249463846CDF8BC +:10AE900000C0FFF79EFF2079401CC0B2207103283C +:10AEA00006D06C49B6F95400B1F90010884205DDAE +:10AEB00003202071012501E0002020712846BDE813 +:10AEC000F8832DE9F041044663480078002853D008 +:10AED0005C48006890F83804C0064DD594F93301F9 +:10AEE000002849DAE08F800446D4A08F0025400571 +:10AEF00000D5012504F10C00FFF786FF0346E08F23 +:10AF00004FF0010641044FF002074FF0030C1CD52F +:10AF10002B430BD084F8247140F00400E08794F8B0 +:10AF2000280103281FD284F828C11CE04BF6FB71CE +:10AF3000084040F42050E087002204F58F7120463D +:10AF400000F0A5FE84F81A610DE004F12000FFF77F +:10AF50005BFF012801D1012B0FD0E08F20F480404E +:10AF600040F40050E087E08F400405D53B4810F8DE +:10AF70005B1F41F0040101701AE7002DF3D0E08F50 +:10AF800044F204010843E08784F8247194F828010E +:10AF9000032801D284F828C10021C4F81811C4F88C +:10AFA0001C11C4F82011E168C4F81E1184F8226154 +:10AFB000D9E72DE9FC47234E04460025306890F878 +:10AFC0009E1A8DF8001090F89F1A8DF8041094F8CE +:10AFD000711139B994F872219AB390F831305B1E2F +:10AFE0009A423FD090F83020521E914202D194F8FC +:10AFF000723133B3914206D190F8310094F8721156 +:10B00000401E81422ED001A96846FFF784FE3268B7 +:10B01000B4F952009DF8043092F89C1AB1464843A6 +:10B02000642190FBF1F007B294F871110C48994239 +:10B030001AD294F872619DF800C0664514D20021BE +:10B0400020E00FE004071000D706100030291000A0 +:10B05000A005100028061000470710009055012099 +:10B06000AC06100001253CE0994213D292F8316001 +:10B070009DF8008094F872C1A6EB0808C44509DB6E +:10B08000761EF1B200680EF0B9FAB0F90000B842CD +:10B09000E8DC26E092F830C04E46ACEB0303994260 +:10B0A00007DB94F872C19DF80080C44501D20021ED +:10B0B0000CE0994215DB92F831109DF8002094F8CD +:10B0C00072318A1A93420CDB491EC9B200680EF035 +:10B0D00095FA316891F8301000EB410030F9020C1C +:10B0E000D5E72846BDE8FC872DE9F04F4FF0000B6F +:10B0F00085B00D4681465E464FF0020A4FF00108CA +:10B1000000F58057B0E100BF08FA06F0D7F808163E +:10B11000019001421BD0C6EB061000EB461109EB73 +:10B12000C10404F58C7004902046FFF7CAFEE18F3D +:10B1300048040CD4E0680090039094F8240101289E +:10B1400006D0022804D049077ED504287DD08AE1A4 +:10B15000FF4AB4F95210B2F900209142F7DB0128FE +:10B1600004D104980021016041608160F9480078B1 +:10B1700020B12046FFF7C7FD012807D0F5484178E8 +:10B18000E068FFF771FD012803D00DE084F87681B7 +:10B1900069E1F148006890F8920AC00604D520469B +:10B1A000FFF707FF012833D0EC4A0098B2F90010EE +:10B1B00000B288420DDBB2F90210884209DC009926 +:10B1C000B2F90A300914994203DCB2F90830994205 +:10B1D0005ADAE18F41F00401E1870499E368C1F88C +:10B1E0000630B2F90010884203DBB2F9023098420F +:10B1F00039DD00200095CDE90110DDE9032133465A +:10B200002046FFF71BFE0499834681F80AA02AE135 +:10B21000D148016891F89D2A84F87721B4F852202A +:10B22000A4F87421626EA266E18F41F00401E18707 +:10B230000499E268C1F80620049906228A72049AE9 +:10B2400082F80B80006801E0F1E06BE090F8950A6D +:10B250000095CDE90108DDE9032133462046FFF7DB +:10B26000EDFD8346FFE0B2F90810CDF80880CDE986 +:10B270000051DDE9032133462046FFF7DFFD834619 +:10B28000049804218172EEE0B2F9103098420BDB91 +:10B29000B2F91230984207DCB2F91A30994203DC55 +:10B2A000B2F91830994235DAE18F41F00401E187B3 +:10B2B0000499897A19B90499E368C1F80630049BA6 +:10B2C00083F80A80B2F91010884203DBB2F9123019 +:10B2D00098420EDD00200095CDE90110DDE9032143 +:10B2E00033462046FFF7AAFD8346049880F80A807B +:10B2F000B9E0B2F91810CDF80880CDE90051DDE9C8 +:10B30000032133462046FFF799FD04998346032025 +:10B310008872A8E004980021817228690199084385 +:10B320002861A0E00498807A06280DD08B4A009905 +:10B33000B2F9103009B2994203DBB2F912309942E6 +:10B3400061DD03285BD08EE0834894F861200068BB +:10B3500090F83010491E8A4202D094F8601041B92A +:10B3600090F8920AC00604D52046FFF722FE012875 +:10B3700012D094F87701A0B1B0F1010084F8770100 +:10B380007548CDF80080F3B200680399B0F9962AA9 +:10B390002846FFF71EFD66E06F48006890F89D0A9A +:10B3A000ECE700986D4A01B2B2F91000814203DB6C +:10B3B000B2F9123099420EDD00210095CDE901016C +:10B3C000DDE9032133462046FFF738FD0499834623 +:10B3D00081F80A800FE0B2F91810CDF80880CDE9A5 +:10B3E0000051DDE9032133462046FFF727FD04998C +:10B3F0008346032088725A4880F8008033E004991D +:10B4000081F80A800EE00099B2F91A3009149942C5 +:10B4100003DCB2F91820914225DA012823D10499DE +:10B42000032088720498E168C0F806101BE00098B9 +:10B4300001B24A48B0F91020914214DDB0F912204F +:10B44000914210DA0099B0F91A20091491420ADAEF +:10B45000B0F91800814206DD2969019A114329617A +:10B460003F4981F80080761C97F91006B042BFF67C +:10B470004BAE28686C68A968EB6840EA040241EAB0 +:10B4800003063243374E2A6901D022B105E022B1CA +:10B4900086F800A001E086F80080304A583216682D +:10B4A000B0432860506884436C6090688143A96011 +:10B4B000D0682D498343EB6028690978084305D19A +:10B4C00026492C222C3125480DF0B8FE05B05846EF +:10B4D000BDE8F08F30B5234B0021049A1B78012B77 +:10B4E00001D102B1012190F82421042A2DD11A4A58 +:10B4F000136893F83824520727D5B0F84820B0F8DD +:10B500004A40121B154C248DA2421EDD4FF491724D +:10B51000125C012A01D0022A0AD190F8614090F809 +:10B520006050641B93F84154AC4201DD01210CE0F2 +:10B53000032A01D0042A08D190F8632090F8620011 +:10B54000101A93F841249042F0DC084630BD000008 +:10B5500040061000D7061000040710003029100024 +:10B5600046061000A0051000B906100030B5FF4ACD +:10B570000021136893F8382452072BD590F8242122 +:10B58000042A27D1B0F84820B0F84A40121BF84CE2 +:10B59000248DA2421EDD4FF49172125C012A01D06B +:10B5A000022A0AD190F8614090F86050641B93F829 +:10B5B0004154AC4201DD01210CE0032A01D0042AF0 +:10B5C00008D190F8632090F86200101A93F8412493 +:10B5D0009042F0DC0846B9E72DE9F34F97B0E54813 +:10B5E000002415940078DFF888B301280BD118984F +:10B5F000006940B1DBF804A0DBF80C90DBF81480A4 +:10B60000DBF81C6007E0DBF800A0DBF80890DBF853 +:10B610001080DBF81860179F002507F5805703E2BC +:10B620000120A840D7F80816059001420FD0C5EBBD +:10B63000051000EB4511179800EBC1000290C08F78 +:10B64000410404D4400703D4CB4901200870EAE147 +:10B65000029800F58C7003900298C0680C900790D7 +:10B66000029890F82401012806D0022804D004286A +:10B670002ED005287ED0D6E118981422C1680091FA +:10B68000006901900CA818990DF093FD0DF1300C94 +:10B6900002989CE80E00FFF71DFF012801D10399D5 +:10B6A000487018981422C1680091006901900CA894 +:10B6B00018990DF07EFD0DF1300C02989CE80E00FB +:10B6C000FFF754FF0128C2D103990020C870AAE1F6 +:10B6D0000398807A012801D0032803D1DBF8148075 +:10B6E000DBF81C6018981422C16800910069019071 +:10B6F0000DA818990DF05DFD0DF1340C02989CE831 +:10B700000E00FFF733FF01280CD00398C07810B16A +:10B710000399401EC8709948008830B103990020F1 +:10B72000C87005E000200399F4E70398C07828B9B1 +:10B73000029890F82E110120884004431898142292 +:10B74000C1680091006901900DA818990DF031FDB4 +:10B750000DF1340C02989CE80E00FFF7BBFE0128A7 +:10B7600001D10399487003980079032820D20399E6 +:10B77000C97800E01BE1D9B102990A6B7B490968DD +:10B78000B1F844148A4210DD401C0399C0B203286A +:10B79000087107D002987A49B0F95400B1F9001045 +:10B7A000884205DD0120159002E003990020087110 +:10B7B0000398837A062B27D00C980FFA8AF200B2EE +:10B7C00090420DDB4FEA2A41884209DC0C994FEA8E +:10B7D000294C0914614503DC0FFA89FC614541DA03 +:10B7E000DDE902319042DB68C1F8063003DB4FEA45 +:10B7F0002A4188422DDD03980221EBB2817200209C +:10B8000000900799189891E01898059A016901200D +:10B81000114217D00299002291F82E1188408443DA +:10B82000DDE90201891D00F032FA02984FF6FB3182 +:10B83000C08F084040F400610298C187039901203D +:10B840008870F0E000904948EBB20068B0F9962AA1 +:10B85000D7E703980421EBB2817201200FFA89F235 +:10B860000090CEE70FFA88F20692904209DB4FEA89 +:10B870002842904205DC3014814202DC30B2814221 +:10B8800057DA022B02D0042B04D00BE003990120DD +:10B89000887202E0039803218172DDE90210C96811 +:10B8A000C0F806100398407850BB0398801D0090A4 +:10B8B0000298DBF824100591019090F822110C30C9 +:10B8C0000129009925D007F048FD059988420DDD32 +:10B8D000DDE90010002200F0DAF901984FF6FB31A3 +:10B8E000C08F084040F400610198C1870298C08F62 +:10B8F000000505D5029890F82E1101208840844358 +:10B900000398807A01280BD00120EBB232B200906C +:10B9100077E7B1F90210B0F90200081A4043D4E702 +:10B920000020DDE906210090EBB21898FFF751FAEC +:10B9300079E018980022016905980143189801617F +:10B94000DDE90201891D00F0A2F902984FF6FB31F2 +:10B95000C08F084040F400610298C187039901201C +:10B9600088700298B0F8401000480BE004071000FF +:10B9700030291000A0051000460610000E07100028 +:10B9800028061000006890F84E24914208D90299C8 +:10B9900090F84F0491F828110844029981F8280181 +:10B9A000029890F82E110120884084433BE00398D0 +:10B9B000807A012804D003280FD006280DD032E069 +:10B9C0000398C07878B30298B0F95410B948006869 +:10B9D000B0F8550481420CDC25E00298B0F954100F +:10B9E000B4480068B0F8500481421CDD0398C07868 +:10B9F000C8B1B148008888B9B048007801280DD096 +:10BA0000DDE902010122891D00F041F90298C08F91 +:10BA100020F0040040F400410298C1870298B0F879 +:10BA20005410A0F852106D1C97F91006A842BFF6EA +:10BA3000F7ADA3480CB1012100E000210170159879 +:10BA400019B045E530B59B490A689E49938E088038 +:10BA50001B1A4B8092F8474405198D801B1BCB8025 +:10BA6000528E0881101A48818D81001BC8816DE5B6 +:10BA7000904909688A8E93490884101A488470474F +:10BA80008C4B904A1B6840B171B1598E081A508393 +:10BA900093F84A14401AD083704711B1588E5083DE +:10BAA000F9E70020108303E0108393F84A14084458 +:10BAB000908370477F4A10B4136882499A8E60B1B0 +:10BAC0000882121A4A8293F84A4420448882101B42 +:10BAD000C88293F84D0410BCCAE7002008824A824D +:10BAE0008882CA8208844A8410BC704770B5714C41 +:10BAF000206890F84604FFF7A5FF206890F84B04F3 +:10BB0000FFF7D8FF2068012190F85404FFF7B8FF31 +:10BB10002068002190F85404FFF7B2FF2168694AB9 +:10BB200091F848044043506291F8490410856549F2 +:10BB30002C22A1F12C000DF081FB61480024634D03 +:10BB400004706148142104705E486C602C300DF064 +:10BB5000D1FB5F4804702C7070BD70B586B006468E +:10BB6000142168460DF0C6FB57480024694604704E +:10BB70003046FFF7B9FA054669463046FFF72CFD17 +:10BB800028435249012801D0486805E04948006827 +:10BB900090F84204401F4860002804DD401E4860C1 +:10BBA0004748007800B94C604648142269462C305A +:10BBB0000DF044FB06B070BD2DE9F04700F13806EA +:10BBC0000546B078434F0B460024B8B1424AF1789D +:10BBD0001078401E814258D1C1B2904618460DF0EF +:10BBE00007FD814698F80000401EC1B238680DF08C +:10BBF00005FD034630787278014611E000211846B1 +:10BC00000DF0F6FC81460021F0E700BF19F8006056 +:10BC100095F84770BE4201D1641CE4B2401CC0B22A +:10BC20008242F3D2234E61B13068B0F83A04491E23 +:10BC3000C9B233F91170874203DD641CE4B20029F4 +:10BC4000F5D126480078401E82420DDA31688242E2 +:10BC50000ADA521CD2B2B1F83AC433F9127067450D +:10BC600002DD641CE4B2F2E71D4880F85C403168F4 +:10BC700091F84C14A14208D2A98C41F48061A984A6 +:10BC800010F85B1F41F008010170BDE8F087022346 +:10BC900080F82431002380F828310123C362012A6F +:10BCA00004D00968016280F81831704703220C3013 +:10BCB00007F030BB040710000E0710002605100027 +:10BCC000440610005C29100046061000A005100074 +:10BCD00045061000AC061000850610008606100010 +:10BCE00090550120FBF7DCBD10B54FF4B8519F48CB +:10BCF0000DF000FB4FF49E619D480DF0FBFA9D484E +:10BD0000FF2180F8101600F080FCFEF7D0FBFFF753 +:10BD1000EDFE00F03BF9FDF76CF8FDF798FEFBF740 +:10BD2000C1FDBDE81040FCF791BC70B5924D0024F8 +:10BD30008E48AC7100F06FFC9048007828B18B48B9 +:10BD4000FFF70BFF894800F022F98848FDF75DF8FE +:10BD50008648FDF783FE8A4E307810B98348FBF79A +:10BD60008FFE8348347080F8EC448248B0F81406A3 +:10BD7000A5F81F0070BD2DE9F0417D4C7E4D94F873 +:10BD8000EC04B8B3A8717F487F4F0026067038686E +:10BD900090F88002800703D521467448FEF729FBFE +:10BDA0007349724800F073FC7448007810B16F4812 +:10BDB000FFF7D3FE386890F87E03C00702D06B48C7 +:10BDC000FEF79DF9694800F0E2F8684800F075F95F +:10BDD0006648FDF71AF86548FDF740FE6348FBF733 +:10BDE0004FFE84F8EC646348B0F81406A5F81F0011 +:10BDF000BDE8F081FFE7FFF798FFF4E710B55E4874 +:10BE000000248471594800F006FC5848FCF7FDFFF7 +:10BE10005648FBF7BEFD564880F8EC4410BD10B5FF +:10BE2000534C94F8EC04D8B15349887121464F48DB +:10BE300000F02DFC5448006890F87E03C00702D043 +:10BE40004A48FEF75CF9494800F0A1F84748FCF77A +:10BE5000DCFF4648FBF79DFD002084F8EC0410BD94 +:10BE6000BDE81040CAE710B5414C014694F8EC0417 +:10BE70000F280DD2C0EBC00000EB400004EB8000A7 +:10BE800054220DF0DBF994F8EC04401C84F8EC0427 +:10BE900010BD10B500F580500021D0F80836012201 +:10BEA00002FA01F423420BD18A401343C0F808364A +:10BEB00090F910268A4201DA80F8101648B210BDB7 +:10BEC000491C0F29ECDB4FF0FF3010BD10B500F519 +:10BED000805091F832410123D0F80826A3409A43BC +:10BEE000C0F80826002281F8242190F9102691F943 +:10BEF00032118A4207D1D0F80816B1FA81F1C1F1A6 +:10BF00001F0180F8101610BD30B500F580500022DA +:10BF1000D0F80C46012300BF03FA02F52C4206D1EB +:10BF200093401C43C0F80C4681F8332130BD521CAD +:10BF300052B20A2AF0DBFF2081F8330130BD10B580 +:10BF400000F5805091F833410123D0F80C26A3402E +:10BF50009A43C0F80C26FF2081F8330110BD044835 +:10BF60007047034890F8EC0470470000A0291000C7 +:10BF7000A0401000A0391000905501204707100084 +:10BF800010071000A80510000407100070472DE9E5 +:10BF9000F047054641F20860042128440BF09CFE5E +:10BFA00000240127DFF86C81DFF86C914FF0050A5F +:10BFB00005F580567BE000BFD6F8081607FA04F0B6 +:10BFC000014272D0C4EB041000EB441005EBC00139 +:10BFD00091F82401012804D0022802D0042840D07E +:10BFE00063E091F87601012808D091F82501032833 +:10BFF00008D0042806D001282CD056E0002081F873 +:10C00000760123E0454848F20403B0F90020C88FC8 +:10C01000184203D0424AB2F9002005E0030503D5D7 +:10C02000404A1268B2F95A24030702D53E4AB2F9CF +:10C030000020B1F95230934237DAC00506D5B8F97D +:10C040000000834202DD81F825712EE02846FFF7CB +:10C050003DFF2AE0B1F95220B8F900008242F5DB39 +:10C0600023E091F83C0010F0060F1ED091F83E003E +:10C0700040071AD42E4A2D481278B0F90000012A40 +:10C0800001D1B9F9000091F82521032A02D0022A32 +:10C0900005D00AE0B1F95220B9F9000001E0B1F988 +:10C0A0005220824201DA81F824A1641C64B296F91C +:10C0B0001006A04280DABDE8F087F0B50021012625 +:10C0C00000F5805304274FF00D0C00BFD3F808266D +:10C0D00006FA01F4224218D0C1EB011202EB411220 +:10C0E00000EBC202002592F82441092C06D00A2C4C +:10C0F00004D00B2C05D00C2C03D004E082F8247162 +:10C1000001E082F824C1C2F83851491CC9B20F2994 +:10C11000DCD3F0BD2C0610002E06100028061000FF +:10C1200040061000040710004A06100030061000F8 +:10C130004506100090F83C10090603D5C18F41F068 +:10C140000801C18770472DE9F05FDFF890A615461A +:10C150000C46834601F10C074FF000084FF0FF3901 +:10C1600002F10C069BB3012084F8240195F84600E7 +:10C1700084F8250184F8339184F8288184F8298192 +:10C18000A4F83E80C4F82C8084F8278184F82A81A2 +:10C1900095F8480084F82D01688EA4F85400E868EA +:10C1A000206203223146204607F0B4F803223146CC +:10C1B000384607F0AFF84FF40040A4F85E00A4F84A +:10C1C0005A00401EA4F85C00A4F858003CE0FFE7C9 +:10C1D0001146204600F037FBE06A0322401CE06273 +:10C1E0003146204607F089F803223146384607F0E9 +:10C1F00084F894F82C0184F82D01DAF80000E16A43 +:10C2000090F8DA0381421FD2E089618A401AB4F9BA +:10C210005A1000B2814201DAA4F85A00B4F9581059 +:10C22000814201DDA4F85800A089218A401AB4F99E +:10C230005E1000B2814201DAA4F85E00B4F95C102D +:10C24000814201DDA4F85C0094F82501042851D056 +:10C2500095F8460084F8250195F8460084F82501F4 +:10C2600095F8480084F82C0195F8470084F82E01D1 +:10C27000E88CA4F84000288DA4F84200688DA4F84A +:10C280004600E88DA4F84800288EA4F84A00288BC0 +:10C29000A4F84C00B5F93200A4F85200A969216352 +:10C2A000E9696163296AA163A98EA4F85610A98C73 +:10C2B000A187A96B21666969E16195F8491084F845 +:10C2C0002F1195F84A1084F83011B5F84E10A4F8E3 +:10C2D0004410B4F95410814201DAA4F85400C4F8AF +:10C2E0006C8184F83191A88C8005E08F16D540F4DC +:10C2F000807015E095F84610042908D094F93401AF +:10C30000002801DD401E06E084F82511A4E7DAF8D4 +:10C31000000090F8940A84F834019DE720F48070BE +:10C32000E08755F83C0F6066287A84F87101687AD6 +:10C3300084F872012146584600F05CFA2046BDE8B8 +:10C34000F05FF7E6F0B5B1F90260B2F90250782477 +:10C3500006FB05F7002F2ADDB1F90070B2F900C025 +:10C3600007FB0CF7002F22DD76435D4396FBF5F5C6 +:10C370002DB24580B1F90010B2F9002049435A436B +:10C3800091FBF2F10AB20280782D00DD4480B0F911 +:10C3900002306FF077018B4200DA4180782A00DDAD +:10C3A0000480B0F900208A4200DA0180F0BD00214B +:10C3B0004180FAE72DE9FF4FDFF8248483460F46DA +:10C3C000D8F8040087B00021016000F0CBFA002506 +:10C3D0000BF580564FF00109059088E0D6F8080665 +:10C3E00009FA05F108427DD0C5EB051000EB4511B7 +:10C3F0000BEBC10494F82401072876D0F74805997F +:10C4000001910068214690F88CA3201D06F0A5FF3D +:10C4100000FB0AF0019900FB0AF0884200DA0846A6 +:10C42000EE49096891F87F23920611D5E26A012A44 +:10C430000ED802D191F8D81302E04AB991F8D71377 +:10C44000019A01FB01F101FB02F1884200DA084682 +:10C4500082462246211D684606F075FF221D111DE9 +:10C4600003A806F070FFBDF900006430C82804D8A6 +:10C47000BDF902006430C82801D9012300E003237C +:10C4800003AA694602A8FFF75DFF6088BDF80A109D +:10C490000844ADF812002088BDF8081000240844B4 +:10C4A000ADF810001BE000BFC4EBC40000EB40007F +:10C4B00007EB800104A80C3106F04FFF50450CDA61 +:10C4C000D8F804100A6802EB420201EB4202506005 +:10C4D000547215720868401C0860641CE4B297F836 +:10C4E000EC0400E001E0A042DED86D1C6DB296F9CC +:10C4F0001006A842BFF672AFD8F80400464601689D +:10C5000000297FD000F00AFA00244FF0040A75E0F9 +:10C5100004EB440100EB410090F9085090F909C088 +:10C52000099809FA05F1036848460B4265D10A9A51 +:10C53000D2F8008000FA0CF218EA020F5DD10998D7 +:10C540000B43C84603600A980A9900230068104309 +:10C550000860C5EB051000EB4511CCEBCC0000EBFF +:10C5600040000BEBC10507EB800229465846FFF758 +:10C57000EAFD95F82401032808D0042809D00628EC +:10C580000DD00B2836D00C2834D036E085F8278122 +:10C5900002E0002085F8270185F824A12DE085F828 +:10C5A00024A195F83C0010F0060F26D095F83E0027 +:10C5B000400722D48B48B0F900108B48007801283E +:10C5C00002D18A48B0F9001095F82501032802D05D +:10C5D00002280AD011E08548B5F95210B0F90000E0 +:10C5E00081420ADA062006E00CE0B5F952008842E2 +:10C5F000F8DB02E00C2085F82401641C70680168F7 +:10C60000A14285DC0BB0BDE8F08F754800210170B8 +:10C610004160816070472DE9F041054641F2546068 +:10C620002E2128440CF066FE0024052705F58056CF +:10C6300020E00121D6F80806A140084219D0C4EB39 +:10C64000041000EB441005EBC00191F8240103280D +:10C6500016D0042814D0022815D0092810D00A2892 +:10C660000ED00B280FD00C280DD00D280BD00E2883 +:10C6700009D0641C96F91006A042DADABDE8F08110 +:10C6800081F82471F5E72846FFF720FCF1E72DE952 +:10C69000FC470446002552480F4600950121001D25 +:10C6A000019504F0D7F84E480521083004F0D2F87F +:10C6B00041F254602E2120440CF01CFE484EFF2213 +:10C6C0002D21B0680CF0ECFD357004F580564FF06C +:10C6D0000108D6F8080688B36B4601AA39462046F9 +:10C6E000FFF768FE4FF0050924E000BFD6F80816F2 +:10C6F00008FA05F001421CD00199084219D1C5EB96 +:10C70000051000EB451004EBC00191F8240103284B +:10C7100018D0042816D0022817D0092812D00A28C9 +:10C7200010D00B2811D00C280FD00D280DD00E28BA +:10C730000BD06D1C96F91006A842D7DAD6F8086619 +:10C7400000253AE081F82491F3E72046FFF7BEFB8D +:10C75000EFE700BF009908FA05F008422CD1204607 +:10C76000FFF797FB002827DBC0EB001101EB40111E +:10C7700004EBC109C5EBC50101EB410107EB8102E7 +:10C7800089F83201494601232046FFF7DCFC9EB9B7 +:10C7900017480078012809D109F1280109F10C0096 +:10C7A00006F017FE4846FBF7DDFE28B1B9F83E005B +:10C7B00040F48051A9F83E106D1C97F8EC04A84293 +:10C7C000C8D807480121001D04F05CF80448052181 +:10C7D000083004F057F8BDE8FC870000040710009B +:10C7E000AC05100030061000450610002E061000A3 +:10C7F0004C07100030B5714A91F82C519468635D74 +:10C80000FF2B05D1137863550F2B01D25B1C1370DE +:10C8100091F82C21A25C81F82C2100EB420202F558 +:10C82000805291F83251B2F854360124AC4023437F +:10C83000A2F8543691F82C1141F2726210440A5C4D +:10C84000521C0A5430BD2DE9F041044691F84600CF +:10C8500000260D46012801D184F82A6194F82501AB +:10C86000574FDFF8608101281FD195F84600032853 +:10C870004DD194F82401022804D0032806D00428BE +:10C8800004D01EE02046FCF73AFA0EE0D8F800107B +:10C8900094F82A0191F84B1301F00F01884202D855 +:10C8A0003978012906D084F82A6195F846000328D2 +:10C8B00007D008E0401C84F82A01012085F84600D2 +:10C8C00001E084F82B6194F8250103281FD195F825 +:10C8D000460001281BD194F82401042817D1387888 +:10C8E000B0B9D8F80000B4F954200321B0F852339D +:10C8F0009A4210DA94F82B2190F85403824207D21E +:10C9000085F8461094F82B01401C84F82B01B5E6FD +:10C9100084F82B61B2E685F84610F9E77CB5002172 +:10C920001CE001EB41034A1C00EB430312E002EB65 +:10C93000420400EB44045E686568AE4209DD00967F +:10C940001E89ADF804605D6025891D81009D6560CC +:10C950002681521C04689442E9DC491C02688A4220 +:10C96000DFDC7CBD70B5174D2868B0F882430CF051 +:10C97000FBFD80B128681449B0F88643B0F88A03FB +:10C980000968884207DA0CF0F9FD012803D128680C +:10C99000B0F8880304440D48007810B12868B0F856 +:10C9A00076420CF0EBFD012804D12868B0F884032E +:10C9B00000B1044604FB04F070BD0000AC0510009B +:10C9C0009106100004071000BC0610003805100086 +:10C9D000F0B500240646254620465F4209E000BF28 +:10C9E00036F91130934201DD1D4402E0BB4200DA0A +:10C9F0001C44491EF4D2002C00DA6442AC4200DD33 +:10CA00000120F0BD2DE9F047FF4D002047F6FF79EA +:10CA100001462A464B46FD4CFD4EB4F900403668AF +:10CA2000A4460AE036F91C70974200DD3A469F4260 +:10CA300000DA3B46381841EBE771BCF1010CF1D24A +:10CA4000F44FD21A4FEAE47A7A60224653460CF049 +:10CA50008CFB0FFA80FC00200146224606E000BF56 +:10CA600036F91230A3EB0C03C3FB0301521EF7D2BD +:10CA7000224653460CF079FB0A21386090FBF1F016 +:10CA8000E549E64B4A46A1F8790000200146A44654 +:10CA90001E680AE036F91C30AB4200DD1D469342A9 +:10CAA00000DA1A46181841EBE371BCF1010CF1D21F +:10CAB000AA1AFA60224653460CF057FB05B2002032 +:10CAC0000146224605E000BF36F912305B1BC3FB6E +:10CAD0000301521EF8D2224653460CF046FBB860C2 +:10CAE000BDE8F08730B41446CA4A15689368AB4273 +:10CAF00002DD5B1B834206DCD3685068834204DDA1 +:10CB0000181A884201DD012200E00022214630BCD3 +:10CB1000C34806F09ABB10B50C46C24909784A00D2 +:10CB20000146C1480CF045FBC04821460078420050 +:10CB3000BF480CF03EFBBF490120087010BDB3494F +:10CB400010B5B1F900104A000146B44800680CF075 +:10CB500030FBB9490120087010BD2DE9FF5FB048D6 +:10CB600000240C38DFF8D49244600470D9F8000037 +:10CB7000DFF8ACA2984690F8EB13264627462546E8 +:10CB80000907AAF1040A16D5A2490A890B88D31A03 +:10CB9000A14A22F8673F8B898988591A518090F8F9 +:10CBA0001224B0F81014D0F80C04FFF79BFF1227E2 +:10CBB0000446012601E08AF80450D9F8000090F8F4 +:10CBC000A502400701D59E4805708CBBDFF874B202 +:10CBD0009BF8000010B99BF8010018B10098F9F714 +:10CBE00004FC0AE09848007818B10021062005F0FE +:10CBF000E7FE95480570954805709BF8001011B93F +:10CC00009BF80100A0B1D9F80000DFF844B290F819 +:10CC1000EB03C0070DD08F4A8F49DBF8000000F00E +:10CC2000D5F804004FF030074FF0010603D012E0B2 +:10CC300024E08AF80150D9F8000090F8EB0380074F +:10CC400009D5844A8449DBF8000000F034F9312723 +:10CC50000446012601E08AF802506CB9D9F80000B8 +:10CC600090F8EA03400707D57A497B4800F060F95D +:10CC700021270446012601E08AF803500CF08AFCC3 +:10CC8000764BDFF8DCC1012118707648012C08D101 +:10CC9000D9F8002092F857241AB18CF800100280BD +:10CCA00007E0028812B1521E028001E08CF80050A9 +:10CCB0007CB3D9F8002092F8F021120600D576B99D +:10CCC0006EB188F800503946052005F079FE0098CD +:10CCD000FFF735FFDDE90101FFF71DFF15E088F8DB +:10CCE00000104F490C390F704A6842F002024A6046 +:10CCF000D9F8000090F85032DB0703D190F8800299 +:10CD0000C00702D042F008004860012004B0BDE82E +:10CD1000F09FFFE788F800501878F7E72DE9F05FFB +:10CD2000DFF8FCA00024AAF10C0ADFF81091CAF881 +:10CD3000044083468AF80040D9F800000E46274692 +:10CD400090F8EB132546A04649060BD590F8192418 +:10CD5000B0F81714D0F81304FFF7C4FE12250446E8 +:10CD6000012703E02E49091F81F804800CF012FC12 +:10CD700001463A480170E4B17FB186F80080D9F8E5 +:10CD8000000090F8EB03C00603D52946052005F006 +:10CD900017FE5846FFF7D3FE09E0012030708AF8ED +:10CDA0000050DAF8041041F00201CAF80410012022 +:10CDB000ADE786F800800078A9E7194900200C3912 +:10CDC0004860087008310860087170472DE9F74F16 +:10CDD000DFF868900B468246D9F80010114800260B +:10CDE000B1F9F27391F8F683B1F9F453027834464D +:10CDF0003946184600F0C0F883460C483946027898 +:10CE0000029800F0B9F82FE00080FFFF96061000AE +:10CE1000B00610002C14012090550120B40610001B +:10CE2000C405100085061000006F01208606100062 +:10CE30002A6F012045071000440710000407100066 +:10CE400042051000A85110003805100026051000FA +:10CE5000A8061000FA0C0120D00C01204E0610008C +:10CE60000C0710000E0710000146BBF1000F00D0A8 +:10CE7000A1B94E4852460024B0F9000009E000BFB5 +:10CE800032F91010002900DA4942A94201DD641C80 +:10CE9000E4B2401EF4D2444500D90126D9F800007E +:10CEA000324690F8F713424806F0CFF9414981F82D +:10CEB0003140BDE8FE8F2DE9F047DFF8FC80844665 +:10CEC0000B46D8F800003949002590F8FC73B0F9FA +:10CED000FA6391462C46B0F9F803B1F9001006E068 +:10CEE0003CF91120002A00DA5242824213DC491E2A +:10CEF000F6D2324831460278184600F049F8044626 +:10CF00002F4831460278484600F042F82044C4B227 +:10CF1000BC4200D90125D8F800002A4690F8FD133C +:10CF20002348401C06F091F9224981F83240D7E5A8 +:10CF300070B5214C05460E462068B0F90934B0F9A9 +:10CF400007241E4801782846FFF742FD0546206861 +:10CF5000B0F90934B0F90724194801783046FFF7D1 +:10CF600037FD40EA0502206890F80B14BDE87040D8 +:10CF70000F48801C06F069B906E000BF30F9123096 +:10CF80008B4201DD01207047521EF7D2002070470E +:10CF900010B50346002005E033F912408C4201DD54 +:10CFA000401CC0B2521EF7D210BD00009606100001 +:10CFB000C1051000905501200407100085061000DF +:10CFC000860610002DE9FF4F93B000200E90834697 +:10CFD000049005909C48894616460068B0F8C00247 +:10CFE0000D90897850680CF0FBFA0A9099F80210BD +:10CFF00030680CF0FDFA099099F8020047E000BF94 +:10D0000099F8004034E01398224600EBC800002154 +:10D01000D0E9005701200CF095F805400F403D4342 +:10D0200025D00A980D9930F91400009088421EDD31 +:10D030008548006890F8F70200070AD50998005D56 +:10D04000CF287BD028B196F84B10884201D0002021 +:10D050000090009904988B4404FB0100049005980B +:10D0600008FB010005900E98401C80B20E90641CD5 +:10D0700099F80100A042C6DA74490A98097800EBD1 +:10D0800041000A9009982830099008F1010099F8A8 +:10D09000031080464145B3DA6B48002504680598C3 +:10D0A000A18EC217A1FB003705FB007001FB020136 +:10D0B0004FF6FF77A3FB070C01FB07C103FB05112C +:10D0C00094F8313030345B1E8BFB03230CF04DF8A9 +:10D0D0007A108018B94641F100014A4600230CF04D +:10D0E00044F8804604986188C217A1FB003705FB0D +:10D0F000007001FB02024D46A3FB050702FB05720F +:10D10000002103FB012123785B1E8BFB03230CF022 +:10D110002CF86A10801841F100014A4600230CF0F7 +:10D1200024F8C6F81CB00E993185169948601699F6 +:10D13000C1F8008017B0BDE8F08FFFE700200F9026 +:10D14000451E089008EB0507F9B230680CF050FA5C +:10D150008246F9B270680CF043FA4FF0FF31631861 +:10D160001AF803208AB1CF2A0FD096F84B70974255 +:10D1700005D130F81370089A3A4492B2089230F808 +:10D1800013300F9A1A4492B20F92491C49B20129E6 +:10D19000E5DD6D1C6DB2012DD4DD089800283FF44B +:10D1A00058AF009948430F9990FBF1F050E710B544 +:10D1B0002549436800220968002B01DA426003E038 +:10D1C0004C8EA34200DD44600368002B01DA02604C +:10D1D00010BD898E8B42FBDD016010BD7CB514460D +:10D1E00000256B46FFF7EEFE19480178164829B175 +:10D1F000016891F80715090700D5042594F8461031 +:10D20000032902D0012907D00FE0006890F8070534 +:10D21000C0070AD0294605E0006890F807054007D6 +:10D2200003D50221684601F029FF6846FFF7BFFFDA +:10D230000198E0810098A08194F82400C00601D4F0 +:10D24000E06860617CBD00000407100086061000E5 +:10D25000440610002DE9F047054690F802800F467D +:10D2600088681446012641460CF0BAF98146A8F1B7 +:10D270000100C1B2B8680CF0B3F9297809EB41029A +:10D2800032F9022CA24203DB30F91110A14200DA7C +:10D290000026697809EB4102B2F90220A24203DBC1 +:10D2A00030F91100A04200DA002695F80380B86832 +:10D2B00041460CF095F9814608F10100C1B2B86809 +:10D2C0000CF08EF9297809EB410232F9022CA242C6 +:10D2D00003DB30F91110A14200DA0026697809EB6E +:10D2E0004102B2F90220A24203DB30F91100A04250 +:10D2F00000DA00263046BDE8F0872DE9FF4F97B0F1 +:10D3000099469246FE48DFF8FC83012204685146A4 +:10D31000D8F8000001F040FBFB480068B0F9B919EB +:10D32000119190F8B8090A90F8489AF802709AF8A2 +:10D33000036000789AF800B09AF80150401E8742C6 +:10D3400001DA7F1CFFB20EB1761EF6B2F049097801 +:10D35000491E8B4503DA0BF1010000F0FF0B0DB104 +:10D360006D1EEDB2B81EC1B2D9F808000CF038F944 +:10D370000B90781EC1B2D9F808000CF031F9049076 +:10D380003946D9F808000CF02BF90190781CC1B28D +:10D39000D9F808000CF024F90290B81CC1B2D9F8F1 +:10D3A00008000CF01DF90390394617980CF012F99B +:10D3B0000890D448394600680CF01AF986460020D7 +:10D3C0007AB2D44F0C90B7E04FFA8BF094E0002182 +:10D3D0000EF800100899189B095C994275D1DFF886 +:10D3E00028C3019BDCF800C033F91030BCF8BBC97E +:10D3F00063456ADA00211491139111991944049B31 +:10D4000009B233F9103010938B4206DD029B33F9D9 +:10D4100010308B4201DD01231393019B03EB40038A +:10D4200033F9028C884507DDB3F902C08C4503DD72 +:10D430004FF0010CCDF850C0012A0FDDDDF82CC0F3 +:10D440003CF910C08C4509DDDDF808C03CF910C07E +:10D450008C4503DD4FF0010CCDF84CC0DFF8ACC2B9 +:10D460009CF800C0ACF1020C62450DDADDF840C05A +:10D470008C4509DDDDF80CC03CF910C08C4503DD9E +:10D480004FF0010CCDF84CC001280BDD33F904CC72 +:10D490008C4507DDB3F902C08C4503DD4FF0010C6C +:10D4A000CDF850C0DFF868C29CF800C0ACF1020CA7 +:10D4B000604505DA884503DDB3F904308B4212DCA0 +:10D4C000149981B913990DE0FFE799B90199B7F95A +:10D4D000003031F9101099420CDA8B49096891F843 +:10D4E000AD19C90731B101210EF800100C99491C82 +:10D4F00089B20C91401C40B2A8427FF768AF8448C3 +:10D500000B990EF1280E007801EB40010B91049964 +:10D5100001EB40010491019901EB40010191029955 +:10D5200001EB40010291039901EB40000390089840 +:10D530002830521C52B20890B2427FF745AF0A9988 +:10D540000C9888422AD9002084F80E01DAF80000ED +:10D5500020606C4800231A462146006801F0C3FB96 +:10D56000012517E004EB85000646514600F07AF8E5 +:10D5700070B104EB4500B0F8B4100A98814207D9A5 +:10D580003046B7F900204946FFF764FE012806D06F +:10D590006D1CEDB294F80E01A842E3D200201BB03E +:10D5A000BDE8F08F2DE9F041574E0F4680463168B7 +:10D5B000144659481D469A69B1F8B53900789A421F +:10D5C00010DCEA8C042A0DD96278237891F8B71917 +:10D5D000D21A521C8A4205DCE278A378D21A521C75 +:10D5E0008A4202DD0020BDE8F0810028FBD14948D5 +:10D5F0002946B0F90020204600F048F80028F2D172 +:10D60000316891F8AC198907EDD52B462246394689 +:10D610004046BDE8F04170E62DE9F0471F00089E46 +:10D62000154681464FF000080CD42C7807E0F9B27B +:10D6300048460BF0DDFF00F80480641CE4B2687813 +:10D64000A042F4D2002E0CDBAC78474606E021461F +:10D6500048460BF0CDFF641C8755E4B2E878A04241 +:10D66000F5D248E602780B789A420BD942784B788B +:10D670009A4207D282788B789A4203D9C078C978C7 +:10D68000884201D300207047012070472DE9F84FF0 +:10D6900004461B48DFF86C8091468B4605680122E2 +:10D6A0002146D8F8000001F077F90027A6784FF05E +:10D6B000010A1DE03146D8F800000BF099FF0090F8 +:10D6C0003146DBF808000BF08BFF0146207852460C +:10D6D00009E000BF31F910C0CC4502DA009B0127F8 +:10D6E0001A54401CC0B263788342F3D2761CF6B25F +:10D6F000E078B042DED2012F3ED100200EE00000E3 +:10D70000FC051000E4051000040710008506100059 +:10D710008606100048061000C505100085F80E01A9 +:10D720002068286000231A462946D8F8000001F036 +:10D73000DAFA0126DFF848801AE000BF05EB860719 +:10D7400021463846FFF78EFF80B105EB4600B0F862 +:10D75000B410D8F8000090F8B809814206D93846CC +:10D760004A465946FFF776FD012806D0761CF6B2E8 +:10D7700095F80E01B042E1D20020BDE8F88F00001C +:10D780000407100070B5FE4C00EB4305049E00EB4F +:10D79000830386B18E69A660CE8C6680096861615C +:10D7A000B5F8B410A1801968E16090F80E012070FE +:10D7B0001068206170BDA6688E616688CE84666937 +:10D7C0000E60A188A5F8B410E1681960217880F88E +:10D7D0000E112069106070BD0146002091F82410E0 +:10D7E000099B1F9AC90610D4D9B2D2B2514301295C +:10D7F0000BD1E4498A78002A07D14978002904D15D +:10D80000E1490978002900D1012070472DE9F0474E +:10D810000F46994614469178089E0BF0DBFE0546AC +:10D82000A17870680BF0DCFE0646A178D7480BF0B3 +:10D83000DFFE0146A2781CE0207800230DE000BF47 +:10D8400015F800C0BC4506D136F91080C84501DB8B +:10D850000F5400E00B54401CC0B294F801C0844542 +:10D86000EED2CB48521C28310078D2B206EB4006EB +:10D870002835E0789042DFD2BDE8F0872DE9FF4FF0 +:10D8800083B00C461E469978129F109D0BF0B0FE97 +:10D890000090B17820460BF09DFE8346B178786801 +:10D8A0000BF09EFE81464FF0000ABA48CDF804A066 +:10D8B000C7F818A000682860B0784FE034783EE0E0 +:10D8C0001BF804000599884237D139F914101198D2 +:10D8D000814220DD0099059808552978204605F0F9 +:10D8E000ACFC28706978204605F0ABFC6870A9781C +:10D8F000404605F0A2FCA870E978404605F0A1FC7E +:10D90000E8700AF101001FFA80FA39F91400B969C8 +:10D910000844B86102E000990020085597F84600D5 +:10D9200003280AD19C4939F91400B1F90010884242 +:10D9300003DB0198401C80B20190641CE4B2707853 +:10D94000A042BDD20098924928300090097808F191 +:10D9500001000BF1280B09EB4109C0B2F1788046B8 +:10D960004145ABD2A7F826A00198A7F84E0007B012 +:10D97000BDE8F08F2DE9F043814693F84600874ECD +:10D98000ABB01C4615468846032832D1E08CA4F87B +:10D990004C002868E0633368B4F93210642293F8CD +:10D9A000BD0293F84B3A484390FBF2F007B27A4835 +:10D9B000642BB0F9000005D8594391FBF2F10BB28A +:10D9C000834200DA03462A46414648460094FFF760 +:10D9D0001DFFB4F93600B8420BDA03A8CDE9000701 +:10D9E00049462B46424602940846FFF747FF0398F4 +:10D9F00028606B4F387808B9787860B1306890F853 +:10DA00003002000707D523462A4641464846F7F725 +:10DA1000AAFE002854D063480178042029B139783F +:10DA200019B161490978012904D094F846100329F5 +:10DA300005D00CE03268E18C92F87A2203E032687B +:10DA4000E18C92F81F23914201D984F84600574B8C +:10DA50002A464146484600F06AFF002830D084F844 +:10DA60004B802868A06322462946504800F02AFED1 +:10DA70004F492046FEF7A0F858224E4914A80BF053 +:10DA8000DDFB50224C4968460BF0D8FB4A48083869 +:10DA9000D0E900232046FFF79FFE012803D1294645 +:10DAA000424800F0DDFE2946404800F0D9FE2246FB +:10DAB00029463E48FFF792FB2046FEF7D4F90120A5 +:10DAC0002BB0BDE8F0832DE9F0410D461F46164608 +:10DAD000044654210BF00EFC002084F84600374821 +:10DAE00000686060A06006EB450084F8485030F89C +:10DAF000B41F61850088E08406EB8500006820641F +:10DB00002F480088E0861E48816921600121A940D4 +:10DB1000394201D0406A2060BDE8F0812DE9F0472C +:10DB200089461C461646274D03F1440891780BF0B0 +:10DB300051FD0746B17860680BF052FD02460020A7 +:10DB4000A061B17845E0307814E000BF17F800C05C +:10DB5000CC450DD132F91030D4F818C0AB429C44FA +:10DB6000C4F818C004DD88F800001D4688F80110CC +:10DB7000401CC0B273788342E8D20548007823E0A5 +:10DB8000C80510004007100038051000D417012008 +:10DB900086061000CA9501002E061000040710002A +:10DBA000A851100024051000260510009045100013 +:10DBB0003C14012008241000B8231000A80610000F +:10DBC000360610000080FFFF491C02EB4002C9B27C +:10DBD0002837F0788842B6D2FE486586B0F9000052 +:10DBE000854202DD012084F8500045E62DE9FF4121 +:10DBF00017460AAA804692E83100F74A1E46B2F953 +:10DC00000020824202DB002004B085E703AACDE9B0 +:10DC1000002002943A464046FFF730FE0121286872 +:10DC2000B94008432860C4F80080E08C10B1039824 +:10DC30003060E8E70120E7E72DE9FF4F81B090462B +:10DC40000E9C8B4604EB880094F80E71DDF840A022 +:10DC500000681E46206001232146584601F043F823 +:10DC6000019858451FD0B5781AE0294601980BF065 +:10DC7000BFFC8146294658460BF0BAFC0146307875 +:10DC800009E000BF19F80030434502D10B5C09F8E8 +:10DC90000030401CC0B272788242F3D26D1CEDB2EB +:10DCA000F078A842E1D294F80E0100250121B84293 +:10DCB00012D0119878B17F1CF8B208E0DAF8002091 +:10DCC00001FA00F31A43401CC0B2CAF8002094F8CD +:10DCD0000E218242F2D2012500914346524620464F +:10DCE0000F99FFF74FFD284605B041E610B5BB4A36 +:10DCF000BB4C1368647893F81E2354B191F8241038 +:10DD000011F0090F02D093F8211301E093F82013CA +:10DD10000A44B449097809B193F86F22904201D9B5 +:10DD2000012010BD002010BD2DE9F0411C46154614 +:10DD30000E46074601F032FAA848E28C016891F8D5 +:10DD40002803824244D8032084F8460091F8F60262 +:10DD50000022830701D4400700D50122DFF880C2EA +:10DD6000B1F82203B1F826339CF801C0BCF1000FD2 +:10DD700008D0DFF874C29CF806C0BCF1000F01D1D6 +:10DD8000B1F8240399490978012903D1984201D9AE +:10DD9000C01A80B2A18D814203D29548007800B9A3 +:10DDA0000022608D03280CD3A08C10F4C07F08D112 +:10DDB0003AB123462A4631463846BDE8F04102F0E2 +:10DDC000B0B823462A4631463846BDE8F041D1E591 +:10DDD000042084F84600F4E78348C07858B17F48AF +:10DDE000844A0068126890F85713914207D290F85D +:10DDF0004003800703D58049002008707047012048 +:10DE0000704791F82410754ACB077C49126809784D +:10DE100006D011B192F8481305E092F8491302E0D8 +:10DE200059B192F846136E4B5B7813B192F84A23BE +:10DE30001144884204D90120704792F84713F2E751 +:10DE4000002070472DE9FF4F834687B066480027C2 +:10DE50000C46DDF850A001790126154606FA0AF6AF +:10DE6000B946E9B366486749B0F90000B1F9001056 +:10DE7000884237DA2968314234D1E18C042931D91A +:10DE80008DE83100DFF8808152460A9BD8F81810DF +:10DE9000D8F82400FFF7AAFE070023D12346206804 +:10DEA00051460A9AFFF77EFB58490870C0B1781EA8 +:10DEB0008DF810008DF814004848006890F8AD09FE +:10DEC000800709D552480078042805D105AA04A97D +:10DED0000A98F6F710FF50B1A08C40F0800000E0E7 +:10DEE00000E0A084A08C10F4C07F20D02AE0494933 +:10DEF0009DF9103001F8363F9DF9140048700090EC +:10DF0000206859460A9AFFF787FB01A8CDF800B0B0 +:10DF100080E830025246216804F14003D8F8180026 +:10DF2000FFF78AFE0028DDD001200BB020E528682D +:10DF3000304207D053462A4621465846CDF8009035 +:10DF4000FFF720FC3846F0E72DE9F04FDFF8B4A0EA +:10DF50003149E9B0BAF90000B1F900102F4ACDE912 +:10DF6000631011802E494FF00008C34608802648F0 +:10DF7000C146474601211C3002F0B6FC224801216F +:10DF8000243002F0B1FC20480221203002F0ACFC29 +:10DF90000221244802F05EFC0421234802F05AFCCE +:10DFA000194C4FF466752946E0690BF081F9294652 +:10DFB000606A0BF07DF91D48B0F900004100206A4D +:10DFC0000BF076F929461A480BF072F929461948E0 +:10DFD00032E000002806100036061000040710008A +:10DFE0004007100042051000A8511000B8061000AC +:10DFF000440610001C0610008F0610009106100049 +:10E00000480610002E061000C8051000C5051000B7 +:10E01000E804100090550120300610003E06100064 +:10E020003C061000F0051000FC05100096061000DC +:10E030003C140120D41701200BF03AF9A821FE4826 +:10E040000BF058F900266670F7F730FBF6F7ECFD99 +:10E05000FA488DF87E61012300681C9000221CA9FB +:10E06000A06900F040FEF64805960025B0F90010C2 +:10E07000BAF9000005F0E1F80FFA80FA9DF87E0188 +:10E08000012801D9EF48067017A8012461904CE1DE +:10E09000002001901CA800EB840060901CAA21467F +:10E0A00007A8059BFFF70FFD07AB2146609A07986D +:10E0B000FFF734FD01200090234605AA07A91CA8FC +:10E0C000FFF760FB18A800F0A5FB78B1BDF8400091 +:10E0D00040F00100ADF8400007A800F034FD28B181 +:10E0E000D948DA4900880880D9490880D948007899 +:10E0F00038B1BDF8400010F0060F02D1D6480068D4 +:10E100000890609800F098FB28B1BDF8400040F0FE +:10E110000800ADF84000BDF94E10514575DD009482 +:10E1200005AA07A91CA8609BFFF78CFE00287DD1DB +:10E130000120A04005990390084241D1BDF840005C +:10E1400010F4C07F3CD1C24805AA07A9B0F900006D +:10E150008DE80700C1482246609B8169406AFFF74D +:10E1600045FD0190BA4803990088ADF85200059A20 +:10E17000114223D0BA49BDF84220096891F82833EA +:10E180009A4205D891F8F6128A0717D4490715D490 +:10E19000012305AA07A91CA88DE80F00AF48224655 +:10E1A000619B416A8069FFF747FD01900120009063 +:10E1B000234605AA07A91CA8FFF7E4FA0198E8B9C5 +:10E1C000BDF8420007A9FFF791FDB8B19DF86C00BA +:10E1D00058B907A80090A3482146619AB0F90030C9 +:10E1E0009E48806900F0A7FA074607AB2146609A6F +:10E1F0000798FFF799FD4FF0010880E0234605AA34 +:10E2000007A91CA80096FFF7BDFA9649BDF94E0074 +:10E21000B1F90010884272DDFFF7DEFD00286ED0F4 +:10E220009DF86C0000286AD1012000E07BE0A0404E +:10E2300005990390084232D18A4805AA07A9B0F986 +:10E2400000008DE8070085482246609B8169406A8E +:10E25000FFF7CCFC019083480088ADF8520080485D +:10E26000006890F84003C00619D4059A039810423C +:10E2700015D0012305AA07A91CA88DE80F0077482F +:10E280002246619B416A8069FFF7D6FC019001201C +:10E290000090234605AA07A91CA8FFF773FA019866 +:10E2A00030BBBDF8420007A9FFF7ABFD00B30798EC +:10E2B0000090DDF8809107A8019001208DF86200A0 +:10E2C000DDE900034A46214600F068FF64484A46FB +:10E2D0002146006890F84003C006DDE9000302D53E +:10E2E00001F01FFE01E0FFF745FB4FF0010906E0DA +:10E2F000234605AA07A91CA80096FFF743FA0120A8 +:10E300000599A0400143514A0591639911805049F4 +:10E31000649A0A804B490A782AB105439DF87E0128 +:10E32000012800D90E70641CE4B29DF87E01A04261 +:10E33000BFF4AEAEC1B24C4841714C49A0F81D507B +:10E340004D4881F800B04A4981F80080494981F878 +:10E3500000900770FDF705FE9DF87E214749904229 +:10E3600002D90120087000E00E700221444802F03A +:10E3700089FA0421434802F085FA3848012118300F +:10E3800002F015FB354801211C3002F010FB334828 +:10E390000121243002F00BFB30480221203002F032 +:10E3A00006FB69B0BDE8F08F2DE9F04F00262B4841 +:10E3B000E5B0B146B046264F01211C3002F094FA78 +:10E3C00026480121243002F08FFA2448022120300F +:10E3D00002F08AFA02212A4802F03CFA0421294874 +:10E3E00002F038FA1D4C4FF466752946E0690AF0D0 +:10E3F0005FFF2946606A0AF05BFF2348B0F900001E +:10E400004100206A0AF054FF294620480AF050FFD4 +:10E4100029461F480AF04CFFA82107480AF06AFF66 +:10E420004FF0000A054884F801A08DF87EA15546FA +:10E430000068012352462DE090451000240610008C +:10E440004C061000C50510004206100030061000F2 +:10E450002E06100044061000AC061000C80510007F +:10E460000407100032061000905501208D061000A0 +:10E470008E0610008F06100090061000B8061000DF +:10E48000F0051000FC051000960610003C14012059 +:10E49000D41701201C901CA9A06900F024FCCC48D2 +:10E4A00060950025B0F90010B7F9000004F0C5FE32 +:10E4B00007B29DF87E01012802D9C64880F800A065 +:10E4C0000124A346A7E01CA800EB840005901CAA29 +:10E4D000214607A8609BFFF7F6FA07AB2146059A8D +:10E4E0000798FFF71BFB234660AA07A91CA8CDF8D5 +:10E4F00000B0FFF747F918A800F08CF928B1BDF873 +:10E50000400040F00100ADF84000059800F094F99B +:10E5100028B1BDF8400040F00800ADF84000BDF95A +:10E520004E00B84266DD009460AA07A91CA8059BAE +:10E53000FFF788FC00286CD10BFA04F06099039077 +:10E54000084241D1BDF8400010F4C07F3CD1A24840 +:10E5500060AA07A9B0F900008DE807009F4822468D +:10E56000059B8169406AFFF741FB01909A48609AD8 +:10E570000088ADF852000398104223D09848BDF8A7 +:10E580004220006890F828339A4205D890F8F602A5 +:10E59000820717D4400715D407AA1CABCDE9003277 +:10E5A00060A98E48CDE9021B416A17AB22468069FB +:10E5B000FFF742FBCDE900B0234660AA07A91CA8DB +:10E5C000FFF7E0F8019868B9BDF8420007A9FFF726 +:10E5D0008DFB38B107AB2146059A0798FFF7A4FBDE +:10E5E000012607E0234660AA07A91CA8CDF800A0D1 +:10E5F000FFF7C8F860990BFA04F001436091754980 +:10E600000A7832B105439DF87E01012801D981F8CD +:10E6100000A0641CE4B29DF87E01A042BFF453AF99 +:10E62000C1B270484171A0F81D506F48704980F820 +:10E6300000906E48067081F8008002216D4802F05B +:10E6400021F904216C4802F01DF9644801211830B9 +:10E6500002F0ADF9614801211C3002F0A8F95F48D1 +:10E660000121243002F0A3F95C480221203002F09D +:10E670009EF965B096E65C49002008705B49087019 +:10E680005B490870534908705C4908707047F2E7AD +:10E6900052490020574A08628861C8611060564A92 +:10E6A0001060514A1070514A1070514A1070494A16 +:10E6B000107048707047494900204870A8215048A0 +:10E6C0000AF018BE2DE9F74F44480D4641780F294E +:10E6D00001D2491C417001F0FF094A4982F8479074 +:10E6E00001EB890029680160A97847480AF080FF9A +:10E6F0008246A87819E000982C7800EBC80B0DE052 +:10E70000DBE900672246012000210AF01BFD0640DC +:10E710000F403E4301D00AF80490641C6878A04280 +:10E72000EEDA0AF1280A08F10100E978804641454D +:10E73000E1DABDE8FE8F2DE9FF5F8B461446917844 +:10E740000E9D0AF047FF0646A17868680AF048FF68 +:10E7500007464FF00009FFF73FFB30B12B49B5F9F1 +:10E760003200B1F90010884203DD002004B0BDE89A +:10E77000F09F2748A178E37890F800A019E020786E +:10E7800062780FE016F80080D84509D137F910807B +:10E79000DDF80CC0E04503DD09F1010C1FFA8CF92E +:10E7A000401CC0B28242EDD2491C07EB4A07C9B2F5 +:10E7B00028368B42E3D229464846FFF722FB002841 +:10E7C000D4D0A88C40F40070A8840120CEE70000CB +:10E7D0004C061000C50510002E061000C8051000DC +:10E7E00004071000905501208D0610008E061000C1 +:10E7F0008F061000F0051000FC051000B806100090 +:10E80000904510006C1B01203C14012028061000CC +:10E8100086061000017859B18B4A1278521E914237 +:10E8200006D0407820B189490978491E884201D133 +:10E830000120704700207047017829B18249427851 +:10E840000978491E8A4209D1817829B1C1787F4867 +:10E850000078401E814201D101207047002070479E +:10E86000F0B57B4D002205EBC2060023C6E900335C +:10E87000521CD2B2172AF6D38A782CE000EBC203DE +:10E88000D3E9007657EA060323D074084FEA37032A +:10E8900017EB070E46EB060C44EA0C04344343EA3C +:10E8A0000E0305EBC2063B43D6E9007C1F434CEA4E +:10E8B000040CC6E9007CD6E9027C1F434CEA040C38 +:10E8C000C6E9027CD6E9047C1F434CEA040CC6E985 +:10E8D000047C521CD2B2CB789342CFD200225B4B45 +:10E8E0000AE000BF05EBC20400EBC207D4E90264F2 +:10E8F000C7E90064521CD2B21C78A242F2D3087855 +:10E9000008B1401E0870504A48781278521E904252 +:10E9100001DA401C4870887808B1401E88701A7867 +:10E92000C878521E904201DA401CC870F0BD2DE933 +:10E93000FF5F9478164604EB84028B4600EBC2001E +:10E94000002100F1290820E0002081468246357828 +:10E9500077780FE018F805205A4509D12A4601209A +:10E9600000210AF0EFFB41EA0A0A40EA0909012105 +:10E970006D1CEDB2AF42EDD2039B08F1280803EB0A +:10E98000C403641CC3E9009AE4B2F078A042DBD26D +:10E9900004B00846BDE8F09F70B50C788B784D78D0 +:10E9A000C9789AB10CB1641EE4B2274A1278521E9B +:10E9B000954201DA6D1CEDB20BB15B1EDBB2234A4E +:10E9C0001278521E914201DA491CC9B203EB83024C +:10E9D00000EBC2020026293209E0204602E016546C +:10E9E000401CC0B2A842FAD95B1CDBB228328B4271 +:10E9F000F3D970BD2DE9F0439C7893F803C004EB84 +:10EA0000840500EBC505104890F8009004FB09F060 +:10EA100001EB40060020293512E019785F7808E004 +:10EA200015F80180904502D136F911804044491C07 +:10EA3000C9B28F42F4D2641C06EB4906E4B2283511 +:10EA4000A445EAD2BDE8F0838606100085061000D2 +:10EA5000384610002DE9F04780464A488C780D462C +:10EA60000078801E012C05D9E978814202DA002065 +:10EA7000BDE8F087022C01D2022701E0EF78C4B292 +:10EA80004FF000092146D8F808000AF0A9FD064613 +:10EA90002146D8F804000AF0A3FD01463A4802785E +:10EAA00015E028786B780AE036F910C031F910804B +:10EAB000C44502D04FF0010903E0401CC0B28342BC +:10EAC000F2D2641C06EB420601EB4201E4B2BC4206 +:10EAD000E7D94846CCE72DE9F04780462A480C465E +:10EAE0004E780178891E8E4201DA0020C0E7814607 +:10EAF000CFB24FF0000AA178D8F808000AF070FDF4 +:10EB00000546A178D8F804000AF06AFDA178E378F8 +:10EB100099F8002013E03C460AE000BF35F914C024 +:10EB200030F91480C44502D04FF0010A02E0641CA1 +:10EB3000B442F3D905EB420500EB4200491C8B427D +:10EB4000E9D2504694E70F4A00211278521ED3B200 +:10EB500090F845200AB19A4204D1818C41F002011B +:10EB600081840121084A90F844301278521ED2B2B2 +:10EB7000934204D1818C41F0040181840121084633 +:10EB80007047000085061000860610002DE9F05F32 +:10EB900007460025DFF85CB42DE000BFDBF8081065 +:10EBA0004E5DDBF8041001EB450A1AE00AEB0600A3 +:10EBB000804610F8011C10F8029C084600F00FFA7D +:10EBC0000446484600F00BFA844202D20146204631 +:10EBD0000C46DBF80410761EF6B201F8104008F877 +:10EBE000024C012EE2D804D1284600F0F8F98AF848 +:10EBF00000006D1CEDB2BD42D0D300221146DBF8FF +:10EC000004000DE000EB41031C788C4203D11A7024 +:10EC1000521CD2B202E010F814401C70491CC9B258 +:10EC2000B942EFD300221346114608E010F8114014 +:10EC30009C4202D0521CD2B22346491CC9B2B942EE +:10EC4000F4D3521CD0B2BDE8F09F30B5B0B18842C9 +:10EC500014D002D20A4601461046E64A536803EB36 +:10EC600040031C788C4209D05C788C4206D09568B1 +:10EC70002A5C022A02D2541C2C549954084630BDF6 +:10EC8000F0B503EB8204A57805EB850600EBC6061C +:10EC9000E0782836A8420FD3207807E0371897F895 +:10ECA00001C0944500D17970401CC0B2677887429A +:10ECB000F4D26D1CEDB2EBE703EB81002568056033 +:10ECC00003EB420003EB410130F8B42FA1F8B4206C +:10ECD000C949096821600021018093F80E01401E96 +:10ECE00083F80E01F0BD2DE9FF4F884608460978EC +:10ECF00087B0FF2915D0C14A8A46417812789142DF +:10ED000001D2491C00E01146CDB2BD4990F80290F5 +:10ED1000C0780978884201D2401C00E00846C6B29B +:10ED200004E04FF0000A5546D146564609984FF088 +:10ED3000000B08B198F80EB1AE4C206800F15A01F2 +:10ED4000C4E901015A210AF0B3FAD4E901122C20D6 +:10ED5000002301F810001354401EC0B2F8D20BF18A +:10ED600001000390C0B20090079809EB890100EB05 +:10ED7000C10709F10100029743E000BF0AF1010059 +:10ED80000197C4B2283738E03919086830B3385DC4 +:10ED900030B3CF282FD011F8011C002011B1CF299A +:10EDA00000D008460199095D19B1CF2901D0FFF7BC +:10EDB0004CFF0A9981B101992144059111F8011C78 +:10EDC00019B1CF2901D0FFF740FF0599497819B152 +:10EDD000CF2901D0FFF739FF18B10BE0E41CE4B2F2 +:10EDE00009E000982D2803D2411CC9B2009101E02E +:10EDF000401EC0B23855641CE4B2AC42C4D9049879 +:10EE0000401CC0B20490B042B8D90098FFF7BEFED3 +:10EE1000009003980022C0B2774B09E008EB800114 +:10EE20001C680C6008EB4001401CA1F8B420C0B283 +:10EE300000998842F2D302984F46283001903BE077 +:10EE4000544632E0204401210958E9B3417851B3D6 +:10EE5000CF2928D0674A526812F81110417008EB88 +:10EE6000410008EB810930F8B42F521C028099F858 +:10EE70000010204604F0E1F989F8000099F801102B +:10EE8000204604F0DEF989F8010099F802103846AE +:10EE900004F0D3F989F8020099F80310384604F019 +:10EEA000D0F989F80300641CE4B20198AC42C9D3DC +:10EEB00028307F1CFFB20190B742C1D30098401E9A +:10EEC000C2B288F80E2100E00DE0099800280DD0AC +:10EED000A2EB0B00012809D1099907980BB0434612 +:10EEE000BDE8F04FCCE6E41CE4B2DCE70BB0BDE8D3 +:10EEF000F08F2DE9FF4FAFB01C46012080463C98B3 +:10EF000090F80E11414544DBB82168460AF0F2F949 +:10EF10003C996B4601EB880008F0FF0100682E90D9 +:10EF20002EAA3098FFF703FD80B32EA96846FFF79D +:10EF300097FC9DF8BA1031980AF05AFB82469DF86A +:10EF4000BA001EE068469DF8B85000EBC90B10E00F +:10EF5000DBE900672A46012000210AF0F3F80640A9 +:10EF60000F403E4304D01AF80500401C0AF8050083 +:10EF70006D1C9DF8B900A842EADA0AF1280A09F1E5 +:10EF800001009DF8BB1081464945DBDA08F101001C +:10EF9000B4E7A17830980AF02BFB0546A1782F98AA +:10EFA0000AF026FB0646A17831980AF021FBA278E8 +:10EFB000CF230FE0217806E0475C022F02D36F5C7D +:10EFC00007B97354491C67788F42F5DA2830521C10 +:10EFD00028352836E1789142ECDA33B087E7054AE4 +:10EFE000D2E9011202E000BF11F81000135C002BFF +:10EFF000FAD17047F0051000CA950100860610008E +:10F0000085061000F0B5B2F900400668B44202DD92 +:10F01000B3F9001030E002EB410434F9025CB54270 +:10F0200004DA03EB410131F9021C25E000252C46EE +:10F030004F1E0CE032F914C0B44507DC02EB440C5F +:10F04000BCF902C0B44501DB25460C46641CBC4239 +:10F05000F0DB32F9154003EB450133F91530B1F916 +:10F06000021002EB4502361BC91AB2F902207143A5 +:10F07000121B91FBF2F119440160F0BD2DE9F04142 +:10F0800005463748036893F80705C40603F20F5096 +:10F0900021D5B3F8FA696C68B4421CDBB3F8FC699B +:10F0A000B44218DCB3F8FE692C68B44213DBB3F841 +:10F0B000006AB4420FDC074693F8040A93F8021A78 +:10F0C00093F8052A07EB400093F8034A00EB41064A +:10F0D00007EB420E10E039B302292CD0032935D0BA +:10F0E00004293AD193F8081593F8094593F80E3599 +:10F0F00000EB410600EB430E0A4422440EEB4107AD +:10F10000A02A2ADC012906DD05F1040C034672461B +:10F110006046FFF777FF012C1FDD284633463A464D +:10F120002146BDE8F0416DE793F8081593F80945CD +:10F1300093F80A2505E093F8081593F8094593F824 +:10F140000C2500EB410600EB420ED5E793F80815BD +:10F1500093F8094593F80D25F3E7BDE8F081000029 +:10F160000407100030B542780378CD8CD21AC378EA +:10F170008078521C1B1A5B1C05FB02F0D4185D43FF +:10F1800040006A00B0FBF4F0B2FBF4F2904202D906 +:10F19000C8850A8630BDCA85088630BD2DE9FF4F77 +:10F1A000002783B01546019700973E463C46BB4674 +:10F1B00091780AF00FFA8246AB7895F8039028E030 +:10F1C000297895F801C08E461DE000BF1AF801208D +:10F1D0000498824215D1A1EB0E02521CDDF800808A +:10F1E000A9EB030002FB0288401CCDF80080DDF88B +:10F1F0000480164402FB008200FB00BB04447F1C19 +:10F200000192491CC9B28C45E0D25B1C0AF1280A64 +:10F21000DBB29945D4D24FF47A70704390FBF7F18A +:10F220004FF47A70604390FBF7F34FF47A7201FB6E +:10F2300004F0714390FBF2F791FBF2F6634393FB0A +:10F24000F2F301980099C01B891BABEB0302069CEB +:10F250008B1A00D55B42002800DA404203EB4000E5 +:10F2600011440A18081A521040104FF47A7148439A +:10F2700090FBF2F0C0F57A70A085069907B0284699 +:10F28000BDE8F04F6EE700002DE9F84F9846DDE944 +:10F290000B7A16460B468146FE4AFF48DDF828B039 +:10F2A00012688079B2F9FC5208B1B2F96253FB4896 +:10F2B000007808B1B2F90A53594618460AF08AF99B +:10F2C0000446594648460AF093F981465946DAF809 +:10F2D00008000AF085F9024698F8000098F8011035 +:10F2E0004FF0010A48B92078B04205D1B2F90000C8 +:10F2F000B84201DD89F800A00120E94B93F800C075 +:10F30000ACF1010C614548D114F801C0B44505D1F8 +:10F3100032F911C0BC4501DD09F801A0491EC9B28E +:10F320003BE000BF14F800C0B44535D132F910C03D +:10F33000BC4531DDAC4402EB400B0FFA8CF83BF9D5 +:10F3400002CC4FF0000ECDF800C0C44505DDBBF97E +:10F3500002C0C44501DD4FF0010E012809D93BF977 +:10F3600004CCC44505DDBBF902C0C44501DD4FF046 +:10F37000010E93F800C0ACF1020C604507D2DDF835 +:10F3800000C0C44503DDBBF904C0C44504DCBEF1C4 +:10F39000000F01D109F800A0401C8842C2D9BDE885 +:10F3A000F88F2DE9FF4FBD489BB01D460178B94845 +:10F3B000289F006831B190F80943B0F90AA3B0F969 +:10F3C0000C0325E0B449897931B190F86843B0F96C +:10F3D00062A3B0F964031BE0B24990F8FB42B0F9B4 +:10F3E000FCA20978B0F9FE92012912D190F811130C +:10F3F0000C4490F81213514503DAAAEB01010FFAFD +:10F4000081FA90F81303484503DAA9EB000000B233 +:10F410008146ECB3DDE91C01119108A90F910AA9FD +:10F420000E91A9780AF0D6F80690A978B8680AF083 +:10F43000D7F886469A4847F6FF73AE7895F803B03A +:10F440000078DA430C901AE0297895F801C00DE0B5 +:10F4500010F801801198804507D13EF911009842BB +:10F4600000DA0346904200DD0246491C06988C45AE +:10F47000EED228300C9906900EEB410E761CB34567 +:10F48000E2D20F9803800E980280BDF9280000E0B8 +:10F490000FE0BDF92010401A6043642190FBF1F0A9 +:10F4A00081490988084400B2AC78EE78804624B1DE +:10F4B0000EE07D48B0F90000F6E7CDE900480DF117 +:10F4C0006C0B02979BE807002B46FFF7DDFE01243B +:10F4D00076480078401E86420BD1CDE900680DF1D8 +:10F4E0006C0B02979BE807002B46FFF7CDFE761EBC +:10F4F000F6B2601EC1B2B8680AF072F88346012CF9 +:10F5000006D9A01EC1B2B8680AF06AF8079001E0F7 +:10F51000CDF81CB02146B8680AF062F80D90601C66 +:10F52000C1B2B8680AF05CF80290A01CC1B2B86819 +:10F530000AF056F8069021461C980AF04BF80E90F7 +:10F5400021461B980AF054F88646002015900120A9 +:10F5500014900020139050480079C0B14D480068C5 +:10F5600090F8AC19090712D56A782978521A90F8E0 +:10F57000B719521C8A420ADCEB78AA789A1A521CF4 +:10F580008A4204DCB0F8B509B969814201DD002086 +:10F590001490E9E02878CBE00E990A5C1D998A4224 +:10F5A00076D100211291179116910D993BF910C057 +:10F5B00031F9102002EB0A0109B202EB09031BB278 +:10F5C0008C4507DD029F37F910708F4202DD01275D +:10F5D00012971697E8B3324F3F780C977F1EB842C8 +:10F5E0007DD00D9F07EB4007189737F9027C1097E5 +:10F5F0008F4207DD189FB7F902708F4202DD0127A5 +:10F60000129717970BEB40071A9737F9027C9F4226 +:10F6100008DD029F07EB4007B7F902709F4201DD4A +:10F62000012712971A9FB7F902709F4206DD029FC9 +:10F6300007EB400737F9027C9F4258DC129B43BB23 +:10F64000012C0ED9079B33F910308B4209DD029B48 +:10F6500000E044E033F910308B4202DD01231293C5 +:10F660001693124B1B789B1E9C4209D28C4507DDDA +:10F67000069B33F910308B4202DD0123129316935F +:10F6800001281DD9189B33F9043C8B4218DD0FE08B +:10F690004DE02CE004071000A851100042051000B6 +:10F6A00086061000B80610002E0610008506100011 +:10F6B000189BB3F902308B4202DD0123129317939A +:10F6C0000C9B9B1E98420AD2109B8B4207DD189B15 +:10F6D000B3F904308B4202DD0121179107E0129942 +:10F6E00029B9424503DD01210EF800101FE0F94958 +:10F6F0000B6893F8F7321B0704D5424502DDCF2390 +:10F700000EF80030179A92B1169A82B1149A72B11B +:10F7100001220EF80020139A521C92B2139209682B +:10F7200091F8B82913998A4201D201211591401C00 +:10F7300069788142BFF430AFE748CDF81CB00D992D +:10F7400000780EF1280E01EB40010D9102990BEBB0 +:10F75000400B01EB40010291069901EB400006903D +:10F760000E982830641C0E90B4427FF613AF1598A3 +:10F770001FB0BDE8F08F2DE9F0470446914260D0FC +:10F7800007D901EB0200A0EB0201CAB2A0EB020014 +:10F79000C1B2C1EBC10000EB400004EB8001C2EB41 +:10F7A000C20000EB400004EB8000B1F93250B0F928 +:10F7B000323081469D4200DA4B86CB8CC58C2B447F +:10F7C000CB840B8D058D2B440B854B8D458D2B44A8 +:10F7D0004B858B6985692B448B61C769CE69CB6882 +:10F7E000D9F80C004FEA234C4FEA20480CFB06FCEA +:10F7F000F51907FB08CC9CFBF5FC6CF31F430FFAD3 +:10F8000083FC0CFB06FC00B207FB00C090FBF5F08C +:10F8100060F30F03CD61CB6094F8EC04411E91427C +:10F820000AD0C0EBC00000EB400004EB800148466A +:10F830005422543909F002FD94F8EC04401E84F877 +:10F84000EC04BDE8F0872DE9FE4F0746A1488A4643 +:10F8500000250068B0F8001301FB01F99F49897980 +:10F8600019B1B0F8660300FB00F954464FF0010BE4 +:10F87000A3E000BF0BFA04F0264600906BE0009A6C +:10F880000BFA06F05946104264D0C6EBC60000EBF6 +:10F89000400007EB8000C26820464EE0B0424BD0EB +:10F8A000C0EBC00303EB430307EB8303DB684FEAC2 +:10F8B000234CACEB224C9B1A0FFA8CFC1BB26CF362 +:10F8C0001F4563F30F059E46824BCDF804C01B68AD +:10F8D00093F8F6C2CDF808C05FEA8C6C0AD593F8AD +:10F8E00003830EFB08FC4FF064089CFBF8FCF44417 +:10F8F0006CF30F05DDF808C05FEACC6C0CD593F80B +:10F900000333DDF804C00CFB03FC64239CFBF3FC15 +:10F91000019B634463F31F454FEA254C0CFB0CFC31 +:10F920002BB203FB03C34B4506D2DDF800C001FA3E +:10F9300000F343EA0C030093401C97F8EC34834235 +:10F94000ACD80421684608F0C7F9012802D1009814 +:10F9500040000090761C97F8EC04B0428FD8042148 +:10F96000684608F0B9F901280BD00421684608F070 +:10F97000B3F997F8EC64A6EB0A01884206D187F840 +:10F98000ECA4BDE8FE8F641CE4B201E0009A584686 +:10F9900000FA04F11142F6D0D84609E0009908FABD +:10F9A00006F0084204D0F2B221463846FFF7E3FEE3 +:10F9B000761EA642F2D8641CE4B297F8EC04A0428A +:10F9C0003FF658AFDDE72DE9F04F424C012B24689C +:10F9D00094F80F7394F80E6305D00B784C78404D73 +:10F9E0009C46690C0CE08B78CC78F8E730F91C80E9 +:10F9F000A84500DD4546884500DA41460CF1010C7A +:10FA0000A445F3D9B54200DA3546B14200DA3146B1 +:10FA1000691A7943642591FBF5F131440EB230F94E +:10FA200013500121B54205DD156801FA03FC45EAD2 +:10FA30000C05156030F91450B54205DD156801FA62 +:10FA400004FC45EA0C051560E51A05F0FF09B9F15B +:10FA5000010F37D95D1CEDB230F9158008EB070CAA +:10FA60000FFA8CFCB04511DD00EB450A3AF9028C27 +:10FA7000E04503DDBAF90280E04507DCD2F800C0BA +:10FA800001FA05F54CEA050CC2F800C0651EEDB29E +:10FA900030F9158008EB070C0FFA8CFCB04511DD2E +:10FAA00000EB450A3AF9028CE04503DDBAF9028021 +:10FAB000E04507DCD2F800C001FA05F54CEA050C78 +:10FAC000C2F800C0B9F1020F36D99D1CA4F1020999 +:10FAD00030E000000407100086061000A851100056 +:10FAE0000080FFFF30F915C0B44522DD00EB450B67 +:10FAF000BC443BF902EC0FFA8CFAD64503DDBBF9A6 +:10FB00000280D04515DC3BF9048CD04503DDBBF900 +:10FB10000280D0450DDCD64503DDBBF90480D0451D +:10FB200007DCD2F800C001FA05F84CEA080CC2F86C +:10FB300000C06D1C4D45D5D9002528460CE000BFFE +:10FB4000166801FA03F73E4204D025B90125401C8E +:10FB5000C0B200E000255B1CA342F1D909E62DE903 +:10FB6000FF4FFB488FB0DFF8EC9304684FF0FF3095 +:10FB70000C90002017460A900B901D4604F5887BD8 +:10FB8000012239464E46D9F80000FEF705FF0095E0 +:10FB9000DDE90F123B463068FFF703FC060006D094 +:10FBA000ED4901200870A88C40F08000A884EB4843 +:10FBB000007880B17EB995F8240010F0060F0AD1C4 +:10FBC00039462846FEF746FF060004D13946284646 +:10FBD000FEF781FF0646E248007800B10126DFF813 +:10FBE00084A3DAF8000090F8F70240073DD501231E +:10FBF0000AAA3946DC48FFF7E6FE804600230BAA36 +:10FC00003946DA48FFF7DFFE08FB00F001282CD167 +:10FC1000DAF80000B5F93210B0F8F402814224DAC3 +:10FC2000B8781EE008F0FF010F9809F0E1FC04909D +:10FC300008F0FF01D9F8000009F0DAFC0146387835 +:10FC4000012209E0049BDDF840C01B5C634502D142 +:10FC50000B5C03B90A54401C7B788342F2DA08F14A +:10FC60000100F97880464145DCDA002084F80E0175 +:10FC700038682060B7483346002221460068FFF705 +:10FC800032F894F80E014FF00008012870D9B548F9 +:10FC9000006890F8F70200070CD54FF46671B4487D +:10FCA00009F028FBAB4800943B460168B04A08467F +:10FCB000FFF71FF9FCF755F90090FCF750F9824661 +:10FCC0003A68DDE90F010792AA4B07AAFEF72FFE5B +:10FCD00060B107A9A748FEF7C3FD2A4607A9A548B2 +:10FCE000FDF77CFAE9686961E96929629C48007856 +:10FCF000E8B39C48006890F8F702800747D594F86D +:10FD00000E01012843D94FF00009012610E000BF81 +:10FD1000904804EB8603F2B2A9680068FEF76AFE19 +:10FD200093493C39484541F8260000DD8146761C60 +:10FD300094F80E11B142EBD2B9F1000F20DD894ADF +:10FD400001208B4B86463C3B126817E053F820603D +:10FD50004FF0640C06FB0CF696FBF9F692F808C31C +:10FD6000B4450ADD0EFA00F6DDF830C001E00EE021 +:10FD7000C4E02CEA060CCDF830C0401C8142E5D22C +:10FD800094F80E01012802D9002084F80E017A4867 +:10FD90007B4A0126B0F9001078480591DFF8C4913C +:10FDA000B0F9000008901180764908806EE0542276 +:10FDB0002946584609F042FAD9F8001004EB4600EB +:10FDC000B0F8B43091F8022393425ED901220C9B23 +:10FDD000B2401A4259D0BBF8242042F01003ABF8CD +:10FDE0002430B0F8B420ABF8262091F8F7020007D1 +:10FDF00003D558480168CBF8001004EB8600099041 +:10FE000059460790FFF7AEF95248F1B25B46079AA0 +:10FE10000068FDF783FE9BF8440060B15A490978F9 +:10FE2000491E884207D09BF8450020B15749097800 +:10FE3000491E88420FD1BBF8240040F0010158460A +:10FE4000ABF82410FEF77FFE28B151484C490088DA +:10FE500008804C4908804B48BBF93210B0F90000CB +:10FE600081420CDD3B48F1B25B46099A0068FDF720 +:10FE700081FD012803D108F1010000F0FF0840498D +:10FE8000059808803F4908980880761C94F80E0170 +:10FE9000B0428CD2D9F800004C4690F8F602000728 +:10FEA0000DD5B8F1010F0AD950460099FFF7CBFCE8 +:10FEB000FCF757F801460098081A00F0FF0821687F +:10FEC00091F8F602000613D540460FE0009A02446E +:10FED000D2B2C2EBC20202EB42030AEB830291F8F8 +:10FEE0001F33D28C9A4201D9009817E0401EEDD200 +:10FEF000B8F1010F0AD0B8F1000F05D1DDE90F010B +:10FF00002B463A46FDF736FD13B032E4144800782C +:10FF10000028F9D19AF8EC0400B1401E8AF8EC04EC +:10FF2000ECE7F0B414681C640E4C246894F8F652A4 +:10FF30006E0737D56D0609D5164D6D7875B3B4F8D3 +:10FF40000643154D64432D68A5422BDCF0BC06E644 +:10FF5000FC051000E4051000C50510004406100063 +:10FF60004205100004071000D00C0120FA0C0120FB +:10FF70002C471000904510003E0610003C06100073 +:10FF8000300610002E0610008606100085061000B0 +:10FF90004206100040071000BC061000FFE7B4F84E +:10FFA0000443CEE7F0BCFDF7E5BC00007047F0B5B8 +:10FFB0001446059F0BE000BF31F9145030F914606E +:10FFC00005EB030CB44519DBED1BB54216DC641ED2 +:10FFD000F2D1BD4B1B6893F845301B09C3F11004E7 +:10FFE0000AE000BF31F9125030F912605D4306FBA0 +:10FFF00004552D1121F81250521EF3D2F0BDF0B568 +:020000021000EC +:100000001446059F0BE000BF31F9145030F914601D +:1000100005EB030CB44519DBED1BB54216DC641E81 +:10002000F2D1A94B1B6893F8CA3A03F00F03C3F14E +:10003000100409E031F9125030F912605D4306FBFB +:1000400004552D1121F81250521EF3D2F0BD2DE9A6 +:10005000F8430E46044601F052F9002844D1F00757 +:1000600004D09A492068096800F0F3F8F0063BD5FF +:10007000954D974F2868B0F950100091B0F94E3067 +:100080003A7894492069FFF792FF2868DFF84882A0 +:10009000B0F954100091B0F9523098F800208F490F +:1000A0006069FFF784FF286890F8401089071BD427 +:1000B000310719D58A490978002915D1B0F9C41A30 +:1000C0000091B0F9C23A3A788649A06BFFF797FFE2 +:1000D0002868B0F9C81A0091B0F9C63A98F800201B +:1000E0008149E06BFFF78BFFBDE8F8837F4A10B5CD +:1000F00012780024022A05D0080706D501F0FFF87F +:1001000010B102E0000700D50124204610BD2DE902 +:10011000FF4F7749DDE90D94D1E9015686469346B4 +:100120000020694FDDF83CC028E000BF39F810100E +:1001300034F91030C91A0AB20021002A0EDAC2F1CD +:1001400000083A689246B2F8092B904502DDBAF8E9 +:100150000B1B01E076B90199494207E055B90FFA46 +:100160008EF15A4506DD03998A4201DD09B201E0AC +:100170000FFA8BF1194424F81010401C6045D5DBB0 +:10018000BDE8FF8F2DE9FE4302465A48884600210C +:1001900003785748012B00D10180544B1C784A4BFF +:1001A000022C1B682FD04468641C446093F8CC5A1E +:1001B000B4EB151F00DD4160846805F00F05641C79 +:1001C0008460A54200DA816093F8D24A210710D0FA +:1001D00093F8D35A01888D420BD9491C018093F8BA +:1001E000CD1A04F00F000D09454301F00F044443FC +:1001F00004E093F8CD0A050900F00F04B3F8056B8D +:10020000B3F8077B0AE04160816093F8CB0AB3F84A +:10021000CE6AB3F8D07A050900F00F042C483149B2 +:100220003B460078CDE9002102903246214628461F +:10023000FFF76DFF28482C4A3B460178CDF8008037 +:10024000CDE90121324621462846FFF760FFBDE88F +:10025000FE832DE9F0438146274803781A48052B91 +:10026000006890F844200CD030F9465F02F00F038C +:10027000B0F902602148C3F11004B0F90000024651 +:1002800011E030F94A5F1309B0F90260F2E700BFEC +:1002900031F9127039F912C007EB0508E04511DB9E +:1002A000BF1B67450EDC521EF2D209E031F9102067 +:1002B00039F910505A4305FB0422121121F810207D +:1002C000401EF3D2BDE8F08304071000B40610000E +:1002D00085061000006F0120860610002A6F01209D +:1002E000FC041000766F0120A06F0120E8041000CC +:1002F0000006100038071000840610009606100053 +:100300002DE9FC478146A248A24E88460178306814 +:10031000012511B9A049097811B1B0F9A1420DE048 +:100320009E49B0F99B424978012902D0022903D0A5 +:1003300004E0B0F99D4201E0B0F99F42022101A81A +:1003400000F0D2FA964F42464946B7F9003001987C +:1003500004F0ABF8306890F8A4120A0705D4C90677 +:1003600003D490F8A502C00708D0B7F9000001999E +:10037000009080238B4A084604F0AEF8306890F86D +:10038000A502800609D588480199894A007800901D +:10039000864803780846F6F75AFAB7F90010019A2A +:1003A0000DE000BF32F91100002801DB034600E038 +:1003B0004342A34203DD7F490025088001E0491E36 +:1003C000F0D2022101A800F0F2FA2846BDE8FC872D +:1003D0007048006890F89002400707D56F4876494A +:1003E000C0780978884201D001207047002070470A +:1003F000684810B5006890F89012890727D56F49B2 +:100400000A78521CD2B20A7090F8923293421ED2ED +:1004100000220A7090F850120324C90703D190F803 +:100420008002C00700D00B24EFF7E8FF64480168A2 +:1004300021430160EFF7E0FF1021052002F0C0FA30 +:10044000BDE810404FF48071002006F042BE10BDA0 +:100450004F49514A514809781278437811430B4368 +:1004600056494FF0000208D14B785B1CDBB24B7051 +:10047000052B03D90123437083704A7070472DE91F +:10048000F34F50480027DFF818A190F8008041484A +:1004900081B03C460068B94690F89002C0071AD077 +:1004A00000264FF0010B019D12E028460299FFF74C +:1004B00027FF10F0010F05D00BFA06F03843641C3B +:1004C000C7B2E4B2BAF90000761C05EB400536B2BB +:1004D0004645EADB01E04446FF273B4807704CB144 +:1004E0000094BAF800003B4682B24146019800F001 +:1004F00011F807E02F48B0F90010032002F060FA6D +:100500004FF001094846BDE8FE8F2C4800210170DC +:10051000417070472DE9F003069F002F1AD0012586 +:10052000012F02D01446A9462FE0002410E000BF9E +:1005300005FA04F61E420AD0002C0BD05300624389 +:10054000BDE8F00300EB42011A4608F032BE641C1D +:100550008C42EDDBBDE8F003704700BF002600EBE6 +:10056000440C35460BE000BF09FA05F818EA030F02 +:1005700002D0BCF9008046440CEB420C6D1C8D424D +:10058000F2DB96FBF7F520F81450641EE6D2E1E7A3 +:100590003805100004071000420510004007100045 +:1005A00096061000CE0D012086061000850610006C +:1005B000C60D012014061000870610000C0610005E +:1005C00014071000880610001106100010B5F5F78A +:1005D000DDF9F6F796F8BDE81040F4F723BB2DE9F6 +:1005E000FF5F9A4693460D460320DDF8388006F0FB +:1005F00010FE8B4801680098FFF741FF0446032076 +:1006000006F022FE4CB1FFF723FFFFF7F1FE85480D +:10061000047004B02046BDE8F09FFFF776FF15B1E7 +:10062000284600F02BFCDFF8009200257F4F804E1B +:10063000B8F1000F0ED07F4801784046F5F7CDF9AC +:10064000B87838B1D9F8000090F82802C00701D175 +:100650003570757008F072FF8046FFF7B9FE40EA0A +:100660000804D9F8000090F84003C0070BD0724886 +:10067000007840B90120F070B87808B9787810B1E6 +:100680006E48F5700570002CC1D15246594600984D +:1006900000F038F80446BAE710B500F081F8002001 +:1006A00010BD10B5F6F793FEFDF7F2FFFBF71CFB4C +:1006B000FFF78CFFFFF729FFFCF77FFB594900206C +:1006C00008704870488088808860C860086114316C +:1006D000087088705448006810F8302F4A704078CD +:1006E000C87010BD10B5F6F77AFEFDF7E4FFFBF712 +:1006F000F9FA00F059FCF6F711F84C480021417066 +:10070000817010BD2DE9F8430024804616460F463F +:1007100025468DF80040022006F07BFD3246394622 +:100720004046F6F7EFFC46490128CA7860F3030219 +:10073000CA7029D002282ED0042800D001246B468C +:10074000324639464046FCF708FA40EA04050220E2 +:1007500006F07AFD9DF8000098B1EFF74FFE39489A +:10076000394A0168126811430160EFF745FE3748C6 +:100770000178052002F024F94FF48071002006F082 +:10078000A8FC2846BDE8F88331480570FDF773FFE3 +:10079000FBF7CBFAD3E7FDF7D7FBFBF7ECFACEE795 +:1007A00038B5044600208DF80000022006F031FD27 +:1007B0002046F6F773FD22490128CA7860F3030248 +:1007C000CA7002D0022805D008E0FDF760FFFBF7F1 +:1007D00015FB03E0FDF7E8FDFBF721FB694620462A +:1007E000FCF79CFA0446022006F02EFD9DF800005E +:1007F00098B1EFF703FE1348134A016812681143DA +:100800000160EFF7F9FD11480178052002F0D8F8F2 +:100810004FF48071002006F05CFC204638BD0000DB +:10082000B406100010061000040710004007100066 +:10083000A851100044071000D00610008F061000C9 +:100840009055012014071000BC051000B8051000D9 +:100850004C071000062904D28B4A515C8B4A535C2A +:100860002BB1002101600146482001F060BD864B9C +:10087000083353F821300360854B43F821000120F1 +:10088000505470470A4630B40021062A11D27E4BDC +:100890009A5C72B17C4C0368083454F82240A3423D +:1008A00007D17A4B99547A4B43F82210016030BC3F +:1008B00070470160014630BC492001F038BD2DE988 +:1008C000F0410124714D724F0026285D38B12E553C +:1008D00057F824104A2001F02AFD47F82460641CD0 +:1008E000032CF2DBBDE8F0812DE9F041684D674B48 +:1008F00000270A460C350760596805F1140603F114 +:100900000804012A38D0022A1CD0032A3FD1002231 +:1009100004EB020CDCF800E0BEF1000F07D0521C23 +:10092000022AF5DB042930D301464C2031E055F88A +:100930002240046046F822004FF00330091FCCF833 +:10094000000032E05FF0000204EB020CBCF800E0B3 +:10095000BEF1000F05D0521C042AF5DB0229E3D2B8 +:1009600013E055F82240046046F8220040F20220CD +:10097000ACF80000891E18E05FF0040214F802C011 +:10098000BCF1000F09D0521EF8D2002FAAD10146A7 +:100990004B20BDE8F04101F0CABC55F8225005607B +:1009A00046F822000120A054491E59609AE7F0B48D +:1009B000374E364C002504220C36D0F8003008346F +:1009C00056F822709F4212D1A75C8F420FD1531C60 +:1009D00011D02F4D00232035036045F82230A35459 +:1009E000012911D0022911D0032904D108E0521E97 +:1009F000E6D2002D08D1F0BC01464D2001F097BC95 +:100A0000A01843708370C370F0BC7047A018437087 +:100A1000FAE770B51D4E1E4D0524083620350BE053 +:100A2000305D48B155F824104E2001F080FC315D56 +:100A300055F82400FFF7BBFF641EF1D270BD70B5FE +:100A40000120134B114A002143F820101154401C7F +:100A50000328F9DB012010700C4A05200C4B506074 +:100A60000C330A4C04200B4A083403F11405732696 +:100A7000464302EBC60643F82060215445F8201097 +:100A8000401EF4D270BD0000D09501005006100049 +:100A90007451100070641000F0B5A7B00D46064602 +:100AA00000249821684608F025FCFF4A002168468A +:100AB000137810E001FB03F7224609E007EB020E72 +:100AC00050F822C036F91EE0F44440F822C0521C0F +:100AD0009A42F3DB491CA942ECDB214607E000BF48 +:100AE00050F8212092FBF5F240F82120491C994250 +:100AF000F6DB002117E000273A460CE002FB034C2E +:100B000050F824E036F91CC0BCEB0E0C01D5CCF13A +:100B1000000C6744521CAA42F0DB97FBF5F28A42B4 +:100B200000DD1146641C9C42E5DBB1F5803F03DB30 +:100B30004FF6FF7027B0F0BD88B2FBE7F0B5DB4998 +:100B4000DB4B096891F8A422D20734D0D94A5778F0 +:100B50004FB191F8BB42B1F8B85204F00F02260928 +:100B6000B1F8B64208E091F8BA42B1F8B45204F0D4 +:100B70000F022609B1F8B242DFF83CC39CF800C06E +:100B8000BCF1030F06D191F8BC120FB10A0901E0C4 +:100B900001F00F02A04201DC1A60F0BDA84201DBA7 +:100BA0001E60F0BD001BB11A4843291B90FBF1F0F9 +:100BB00010441860F0BD0020FBE7BC48BD49006848 +:100BC0000A7800F5F970805CC87070472DE9F00F65 +:100BD000DFF8E0A28346B5489AF8007089466FF0C6 +:100BE000004231F817500168002091F80A6291F82C +:100BF00009124FEA11180B071FD001F00F0CAB4C74 +:100C000000210B462468B54294F8084205DBAE1B70 +:100C100006FB08F696FBFCF63444A44E9AF801C095 +:100C2000D0463668BCF1010F96F8F16108D0BCF1EE +:100C3000020F08D006F0030C12E04FF0010CDEE7C3 +:100C4000C6F3810C0CE0C6F3011C09E039F813600F +:100C5000B24201DD32461846B14200DA31465B1C31 +:100C60006345F3DDABF80010A91AA14201DC67452A +:100C700004DD88F80000BDE8F00F9EE7BDE8F00F46 +:100C800070478E4910B50B7888490022012B0968FE +:100C900002D18B4B1B784BB1B1F8FC31834218D297 +:100CA00091F8F0311B0714D5032225E0B1F8023288 +:100CB000834203D291F8F0311B07F5D4B1F800322A +:100CC000834203D291F8F0315B070AD4B1F8FE31C8 +:100CD0000BE0B1F8FA31834205D291F8F0315B07AD +:100CE00001D5022208E0B1F8F831834204D291F82C +:100CF000F001800700D5012272486E4C03789A42B9 +:100D000011D1617899421AD06F4A1278134307D0F3 +:100D10008168491E8160002911DC007860700EE056 +:100D200001708168F7E78AB1022A01D1012B0DD049 +:100D300091F8F61181600270002900DC627063484E +:100D40006278417B62F30301417310BD91F8F711A2 +:100D5000F0E7564A126892F8F021D20607D5421AF7 +:100D6000002A04DCC1EBC1110844C0F3CF10704766 +:100D7000504900204D4A48705249486088600870C8 +:100D8000126892F8A432DB0703D092F8BB22120952 +:100D900000E00022464B1A60C86008614861886123 +:100DA000C861086270472DE9F05F8B463E49DFF865 +:100DB00014914FF0100A0E7805463701002409F10E +:100DC0000C09DFF8008114E0324651462846FFF74F +:100DD00063FE29F81400BBF1010F10D0394B143316 +:100DE00033F81410FFF7B5FF23F8140005EB47059F +:100DF000641C98F801008442E6DDBDE8F09F314BA9 +:100E00001C33EDE738B5294C0020ADF80000206810 +:100E10004FF0000190F8F00180062D4808D5FFF74B +:100E2000C2FF01212B48FFF7BEFF26491C3103E01A +:100E3000FFF7B9FF234914316846FFF7C7FE206862 +:100E40001C4D90F8F001400602D5BDF8004004E0CA +:100E50001C492878143131F810401F48048020467E +:100E6000FFF70FFF2046FFF769FE164928780C317F +:100E700031F810001549A1F81B0038BD2DE9F14FDC +:100E800084B0002002900848102605780D484FEAEB +:100E90000518406890FBF6F106FB11000C49684309 +:100EA00001EB400A8B4619E086061000040710008B +:100EB0003806100040071000840610008D06100050 +:100EC0008E061000600610008C0610009055012060 +:100ED000AC1B0120AC2E0120120610004049049CDE +:100EE000096891F8F011890615D50BF5985101EBB9 +:100EF00040093C48477868007F1C009008E0214684 +:100F00004846009A08F055F904EB450409EB4809F6 +:100F10007F1EF4D2049CDFF8CC9099F801707F1CFE +:100F200024E02F48006890F8F011890615D5D9F80B +:100F3000041000290FDD02996A1AB0F90612CDE9F2 +:100F40000012B0F9043202980BEB400204EB4001AE +:100F5000084603F031FA0BEB480B6A002146504675 +:100F600008F027F904EB45040AEB480A7F1ED8D2A3 +:100F7000D9F804104FF0FF32491C02EB46024846F4 +:100F8000C9F804108A4200DA4660D9F80400B04279 +:100F900006DB05B01449BDE8F04FA1F5985031E7E4 +:100FA00005B0BDE8F08FE3E610B50D4C206890F871 +:100FB000F101C0F30112C0F3810100F0030002F05F +:100FC00035F9084948702068084990F8EB0000F0AE +:100FD00003000870FFF7F1FDBDE81040C8E600000F +:100FE0000407100060061000AC2E0120400710001E +:100FF00010B5FE48FE49002484610C604C600C7200 +:101000000462C461FFF76EFBFFF719FDF948048025 +:10101000BDE8104000F0A5B9F0B5F749F348F94F25 +:1010200091F83020427091F8313083705A4316B2F3 +:10103000468291F83340C47011F82C2F02704A7820 +:1010400002718A784271C9788171EC49416201F27A +:101050003C618162A1F67841C162E9490B6893F86D +:10106000F01109061AD503F5F97593F8F13100224C +:1010700003F0030311465B1C08E000BF15F801C034 +:10108000A44501D10A4603E0491CC9B28B42F5D8F8 +:10109000C271724307EB42010163F0BD0763F0BD0B +:1010A000D54890F82C10D3488170D04902790B7A3A +:1010B00063F300028B7A63F3C3024B7A63F3820219 +:1010C000CB7A63F341020B7B63F34512CE4BDB78A3 +:1010D00003728B7BC3714B7B63F304120271CB7B76 +:1010E000827B097C63F3030261F30712C7498273B1 +:1010F000097880F82810C6490988A0F82910C54940 +:101100000A7890F85B1062F3410180F85B10C249E5 +:101110000A78C17B62F30301C173C0490A78017C7C +:1011200062F30001BE4A127862F34101BD4A1278AF +:1011300062F3C301BC4A21F00401127880F87E20DA +:101140000174BA490A88A0F84020B94A1388038775 +:101150004B88A0F84230538843878B88A0F84430EE +:1011600093888387C988A0F84610D188C187A04991 +:101170008A7980F87B20097A80F87D10AD4909785A +:1011800080F87C10704770B50D4680EA0506F006C1 +:1011900001D5F5F7B6FA964CC5F300102070B006ED +:1011A00001D5F3F73FFDC5F34010607015F048001E +:1011B00000D00120A0719248006890F8AC0900F0BE +:1011C00001002071C5F30020E071C5F340202072BA +:1011D000C5F34000E07070BD2DE9F041834E864CB0 +:1011E000D6E907100843D4E9081241EA020180EA6F +:1011F000010503D111B1FFF7FBFE11E0E8070BD0A9 +:101200008D4F387820B108F0BFF908B90020387048 +:10121000FFF747FAFFF7C7FEE80601D5FFF7D6F953 +:10122000E169B069FFF7AFFFE069B061206A306241 +:10123000606AF061BDE8F041EEE670B57F4D2C6864 +:10124000002C0CD00022A0B2114601F0D9F9286878 +:10125000A043286003D1BDE8704001F043BA70BDDF +:10126000F8B5002601F03CF8012005F0D2FFFFF7A9 +:10127000B3FF5E4C604D94F82000000716D5D5E909 +:101280000E01F3F73AFF5E48006890F840008007CF +:1012900009D5D4E90701FEF729FF012803D1D5E9D3 +:1012A0000E01FEF76FFF66490020087094F82000D9 +:1012B000217F0843C00708D0E8680090D5E9000105 +:1012C000D5E90423FFF78BF90646E06950B14EB922 +:1012D000032005F09EFF4848E169FEF7B8FE0320B1 +:1012E00005F0B2FFFFF7DCFEFFF7A7FFFFF791FB6A +:1012F000FFF7E5FABDE8F840012005F0A5BF3B483F +:10130000417A012908D0817A012905D0C17A0129C1 +:1013100002D0807B002800D00120704708B5FFF77D +:1013200067FE6B4600220B21022005F01BFF009890 +:10133000C00705D00121022005F0F7FEFFF790FF5E +:101340000098800705D50221084605F0EEFE00F062 +:1013500033F800980007E4D50821022005F0E5FEE7 +:10136000DFE710B5264C2148226892F83110417011 +:1013700092F830208270514341822349C978C1706C +:101380000121017141718171017000218182C1735C +:101390000174FFF786F9F3F7DFFC2068294A90F81B +:1013A000381401F0010111702749B0F87600088067 +:1013B000BDE81040FEF7FABD70B5002400F090FFC4 +:1013C000012005F026FFFFF707FF084D95F82000E4 +:1013D000C00704D008480068FFF75EF90446E869D2 +:1013E000A0B39CBB032005F014FF30E0840610007E +:1013F000A85110009055012068761000E8470120A0 +:1014000004071000105601204007100011061000BC +:1014100014061000440610002605100024051000D4 +:10142000380510003E051000390510007406100044 +:101430007C061000D00610004B0710002C0710008F +:1014400038071000470710004807100006E00A4858 +:10145000E969FEF7FCFD032005F0F6FEFFF720FE2C +:10146000FFF7EBFEFFF7D5FAFFF729FABDE870406A +:10147000012005F0E9BE0000687610000D4D002047 +:101480000D4C28602868401C2860EEF7B7FF07F075 +:10149000BCFD0128206809D040F00400206006F05F +:1014A000DCFB00BFEEF7A8FF30BFEBE720F0040045 +:1014B0002060F7E7CC06100010ED00E070B5134C8B +:1014C00025462021114807F0F3FE104800F0E2FC09 +:1014D0002B78421E691C184600F056F918B10120FD +:1014E000216801F06DFA00F0EFFC0028E9D170BD31 +:1014F00038B50C46054605F0ECFD6946284605F072 +:1015000022FE00992142F8D138BD0000B1511000EF +:1015100070B5002300290EDD0278491E092A0AD27F +:10152000914D401C55F8324005EBC2025268914281 +:1015300001D1A0470346184670BD017811B98B4907 +:10154000407808800120704710B5894903780A78EF +:1015500073B1884B1B6893F88B3B1B060CD50AB9FB +:1015600001220A704078012806D1F7F737FB03E023 +:10157000012A01D100200870012010BD10B50178AA +:1015800021B1022906D003290BD106E04078FAF7F1 +:1015900091FA06E04078012101E040780021FAF755 +:1015A0006FFA012010BD0CB5016800918188ADF87B +:1015B000041080798DF806009DF8000000B39DF8B6 +:1015C0000100102803D29DF8020010280CD300203F +:1015D00068490090019009686A4691F8951A1318B5 +:1015E000401CD9700428FADB6348009940F8071FB3 +:1015F000BDF8041081809DF80610817101200CBD9A +:101600005D49C91D087000200CBD1CB50168009122 +:101610008188ADF8041081799DF800008DF80610DE +:10162000E8B354489DF802200068642A01D9642276 +:1016300002E01AB990F81A238DF802209DF80330C1 +:1016400090F8CA29934200D80BB98DF803209DF871 +:1016500004309DF80520934202D80AB10F2B08D917 +:1016600090F8BB2302F00F038DF8043012098DF8B7 +:101670000520022900D821B990F8BE0300098DF891 +:1016800006003D4800990160BDF8041081809DF876 +:101690000610817139490868820708D500E008E022 +:1016A00020F00200086008210120FFF721FF01203F +:1016B0001CBD3149087000201CBD10B502782F48B0 +:1016C000016812B141F0080101E021F00801016058 +:1016D00008210120FFF70CFF012010BD10B5027892 +:1016E0002648016812B141F4007101E021F4007153 +:1016F000016008210120FFF7FBFE012010BD1D49FC +:1017000010B5096891F8931A49070AD50078C207FD +:101710001A48016802D041F4807101E021F480711F +:10172000016008210120FFF7E3FE012010BD70B524 +:101730001349144A037809684FF00004CE010D499B +:101740004FF00105096802D54BB1032301E033B125 +:1017500002231370407881F81A0A012070BD1570B9 +:1017600081F81A4AF9E70000E495010048071000E3 +:101770004607100004071000D006100034071000C0 +:10178000600510004905100010B50C460023A0F1BB +:10179000A001092903D8FE4850F8213008E0C028EC +:1017A0000AD1FB49A0F1C000A1F1040151F8203099 +:1017B0001146204698470346184610BD0020704742 +:1017C00070B5F44C00230029236011DD0278491E16 +:1017D000042A0DD2EE4D401C283555F8324005EB59 +:1017E000C2025268002A03DB914201D1A04703469E +:1017F000184670BD10B500F0FFFB012010BD2DE9AB +:10180000F041064600240078E34D8106274607D5BF +:1018100001242C7000F002FC30B900F0EDFB03E075 +:10182000C00701D001242F703078400701D544F063 +:101830000404DA48042104600120FFF759FE2F70E8 +:101840000120BDE8F08110B510210120FFF750FE06 +:10185000D24900200860012010BD10B501460024C7 +:1018600009782046032918D005DC59B101290CD08C +:1018700002291AD10EE0042911D0102912D0112901 +:1018800013D111E00124002001E00224012000F026 +:1018900084FA0AE004240220F9E7202400E040242E +:1018A000012002E0082400E01024BA4914F0180FC7 +:1018B0000C60BA4C06D010210120FFF719FE002061 +:1018C000206007E02168814204D0206004210120CB +:1018D000FFF70EFE012010BD70B5002300290FDDBB +:1018E0000278491E052A0BD2A94D401C483555F8EF +:1018F000324005EBC2025268914201D1A047034633 +:10190000184670BD10B50078C207A548016802D01E +:1019100041F0020101E021F00201016008210120F3 +:10192000FFF7E6FD012010BD10B50078C2079C4806 +:10193000016802D041F0040101E021F004010160DE +:1019400008210120FFF7D4FD012010BD10B501785A +:10195000CB0793490A6802D042F0080201E022F066 +:1019600008020A600078800702D542F0400001E0DA +:1019700022F04000086008210120FFF7B9FD012096 +:1019800010BD10B5002103780A469C0601D5202120 +:1019900000229C0701D541F002015C0701D541F00E +:1019A00004011C0701D541F00801DC0601D541F016 +:1019B00010015C0601D541F040011B0601D541F044 +:1019C00080014378DC0701D041F480719C0701D588 +:1019D00041F400715C0701D541F480611C0701D519 +:1019E00041F40061DC0601D541F480519C0601D52B +:1019F00041F400515C0601D541F480411B0601D53C +:101A000041F400418378DC0701D041F480319C0728 +:101A100001D541F400315C0701D541F480211C0758 +:101A200001D541F40021DC0601D541F480119C066A +:101A300001D541F400115C0601D541F480011B067B +:101A400001D541F40001C078C00701D041F0807198 +:101A50005448C0E90012012010BD007800B10120F7 +:101A6000514908700120704770B5002300290FDD2F +:101A70000278491E0B2A0BD2454D401C703555F893 +:101A8000324005EBC2025268914201D1A0470346A1 +:101A9000184670BD014600200978052906D23C4849 +:101AA000C83050F82120002108461047704710B573 +:101AB00006F08FF8012010BD10B54FF40061002032 +:101AC000FFF716FD012010BD10B54FF48051002026 +:101AD000FFF70EFD012010BD10B54FF400010020EE +:101AE000FFF706FD012010BD10B50078C00702D039 +:101AF00000F011FA01E000F005FA012010BD10B568 +:101B000000880024C10700D00224810701D544F0D9 +:101B10000404410701D544F00804C00501D544F48C +:101B2000807494B1EEF76AFC20480168214301609B +:101B3000EEF762FC0221052000F042FF4FF48071B5 +:101B40000020FFF7D5FC012010BD002010BD10B50E +:101B500000880024C10700D00124810701D544F08A +:101B60000204410701D544F00404010701D544F003 +:101B70000804C00501D544F4807404B3EEF73EFCBC +:101B80000B48016821430160EEF736FC022111E0A9 +:101B9000309601003C0710004A0710003007100083 +:101BA00034071000600510004707100014071000EC +:101BB000180710000020FFF79BFC012010BD00203B +:101BC00010BD10B500880024C10700D00124810792 +:101BD00001D544F00204410701D544F00404000794 +:101BE00001D544F0080474B1EEF708FC6F480168B1 +:101BF00021430160EEF700FC4FF400110020FFF7D5 +:101C000077FC012010BD002010BD10B50088002415 +:101C1000C10700D00124810701D544F00204410727 +:101C200001D544F00404010701D544F00804C106BD +:101C300001D544F01004810601D544F0200441068A +:101C400001D544F04004010601D544F08004C105EB +:101C500001D544F48074810501D544F40074400535 +:101C600001D544F480646CB1EEF7C8FB50480168BC +:101C700021430160EEF7C0FB80210020FFF738FC14 +:101C8000012010BD002010BD10B500880024C10740 +:101C900000D00124800701D544F0020474B1EEF7AE +:101CA000ADFB4448016821430160EEF7A5FB4FF40A +:101CB00080010020FFF71CFC012010BD002010BD9A +:101CC00010B500780024C10700D00124810701D598 +:101CD00044F00204400701D544F0040474B1EEF767 +:101CE0008DFB3548016821430160EEF785FB4FF419 +:101CF00080610020FFF7FCFB012010BD002010BD1B +:101D000010B500780024522841D01CDC30283AD08D +:101D10000CDC112833D004DC01282DD0102834D15C +:101D20002DE012282BD013282FD128E033282AD0D9 +:101D300004DC312827D0322827D124E0502826D0AF +:101D4000512822D123E0732824D00CDC702821D024 +:101D500004DC53281BD0582817D118E0712819D05B +:101D6000722812D116E0742814D0752812D0762863 +:101D700010D0772809D10DE000F059FB01E000F008 +:101D8000F3FB012401E000F00FFC204610BD00F041 +:101D9000F9FBF6E700F0E7FCF3E7002118B10128B2 +:101DA00001D0022800D10521084670471C07100009 +:101DB000240710002807100020071000204908B54C +:101DC0000020204C08602049206008601F480068FF +:101DD00090F84003C00701D00220206000F027FBEC +:101DE00000F0DDFD6B4600221921032005F0BAF951 +:101DF0000098C00705D00121032005F096F9FFF7F0 +:101E00005DFB009800070BD50821032005F08DF934 +:101E10002068082140F0080020600120FFF768FBDF +:101E20000098C006DED51021032005F07EF9206859 +:101E3000082120F0080020600120FFF759FBD1E7BE +:101E400030071000340710003C0710000407100092 +:101E50001F480021017041708170704710B51C4C03 +:101E60000346A078102814D20F2900D90F21194851 +:101E7000227800EB02100A4600F8011B194607F011 +:101E800098F92078401C00F00F002070A078401CCA +:101E9000A07010BD70B50E4C0025A17891B10D4910 +:101EA000627801EB021111F8015B2A4607F081F913 +:101EB0006078401C00F00F00607072B6A078401E81 +:101EC000A07062B6284670BD014880787047000057 +:101ED000DE061000D151100010B54FF486715E4837 +:101EE00007F008FA5C490120C1F804015B480021B1 +:101EF0004160017007F0ACFA0021BDE810400120FC +:101F000006F06ABA10B572B600205449087007F09E +:101F10009FFA62B610BD10B572B601204F49087025 +:101F20004D48D0F8080108B107F0EEFA62B610BDCE +:101F300010B572B64849494B0A46D1F80841D2F863 +:101F40000021521C202C07D2641C22F02002C1F870 +:101F50000841C1F800210FE0D1F8044122F020022D +:101F6000641CC1F8002124F02002C1F804215A6841 +:101F7000521C5A60D1F80021046801EBC2021460BF +:101F8000406850601878012805D1D1F8080101286F +:101F900001D107F0B9FA62B610BD2F4AD2F8080194 +:101FA00000280ED0D2F8040102EBC000C37923F060 +:101FB0003F03C37192F80821521E02F03F021343FF +:101FC000C371704710B572B62348D0F8081159B1E3 +:101FD000491EC0F80811D0F8042102F1010222F0D4 +:101FE0002002C0F8042105D11C480078012801D145 +:101FF00007F02EFA62B610BD10B572B60020164971 +:102000000122C1F80801C1E940021449486008787A +:10201000012801D107F01CFA62B610BD70B50E4957 +:102020000020D1F80851002D12D00023D1F804214E +:102030000CE000BF01EBC2042678332E02D1647895 +:10204000B52C06D0521C22F020025B1C9D42F1D818 +:1020500070BD012070BD000060540120E406100036 +:10206000064900224FF470430A804B80044BC0E9BC +:10207000003102210172427270470000EC0610002C +:10208000119701002DE9F05FDFF83C92DFF834B2E0 +:102090000F4606464FF0010AA9F10805A846287820 +:1020A0000446072809D2DFE800F004292D49708B87 +:1020B0009C00012E02D0022E13D07EE0002F7CD097 +:1020C000804810300078862809D07E48F9B2103058 +:1020D000FFF7C4FE0121032004F0FBFF6DE00324A1 +:1020E0006BE06878012805D01021764807F0E0F809 +:1020F00000F0A2F8544689F800A05EE0022E5AD003 +:10210000002445E0022E1BD1704C6E48D8F8041014 +:10211000227807F04EF8032189F800102178A9F8F9 +:10212000041098F80000042488F8010088F80040A2 +:1021300033E0002488F801002C70AFE7022E02D0B3 +:10214000012EF6D039E0FFF728FF082170B15D4A73 +:10215000D0E90030C2E90030022289F80020594A53 +:10216000A9F80220A9F80410052426E068780628BA +:1021700004D00022CBF80020CBF80420032289F8F9 +:102180000020A9F80410062417E0022E08D002242B +:102190005FFA80F088F801002C704B48BDE8F09F92 +:1021A0006878042807D00BEB0700394610F8012C9B +:1021B000444807F075F889F800A0A8462878E9E7B0 +:1021C000022E04D0082F8AD1FFF7FCFE87E7FFF725 +:1021D000F9FE98F80000032488F8010088F8004010 +:1021E0005CE7022E4FF00304A4D0D1E73649002269 +:1021F00008390A704A70354A521C4A6034490160F5 +:10220000304981801031C18010210181704710B5A3 +:10221000044607F01DF92B4AD4E90001C2E9000188 +:102220002A480C3807F07AF928480C3806F0C8F923 +:10223000BDE8104007F068B970B5224C1034207822 +:10224000C12824D160781F4D052808D100F020F85E +:102250002048016829608188A9808079A871607808 +:10226000082814D11C4C207858B90F216170002126 +:10227000A1701A49E01C096891F8952A042107F019 +:102280000FF820682860A088A880A079A87170BD88 +:1022900010480178002913D141701049096891F85C +:1022A0001A23827091F8CA29C27091F8BB231309CE +:1022B000437102F00F02027191F8BE130909817196 +:1022C000704700006C550120F8061000E052100025 +:1022D00035200100D0061000D706100004071000BA +:1022E00070B50F4D802128462C8806F0E1FF641C54 +:1022F0002C8070BD0A48001F00210160704708490A +:10230000091F0A88024204D0C87818B1C878401E54 +:10231000C8707047A52088708878A528FCD07047C1 +:102320009055012037480021016041607047C0B2DC +:10233000012200F047FBFEE7344C0025324FC4E990 +:102340000225C4E90071064600682061706860617A +:10235000B068A061F068E061306920627069606215 +:10236000B069A062F069E062294890468946006839 +:102370002063274810380068606325480C380068DF +:10238000A063234808380068E0632148001D006806 +:1023900020641F483438006860641D4814380068A1 +:1023A000C4E9120504F0E5FF2065C4E91565E5659B +:1023B00025666566A566E56625676567C4E91E57F7 +:1023C00041464846FFF7B3FF10B50446C0B20022AD +:1023D00000F0F8FA0F490868082803DA094A14548B +:1023E000401C086010BD012806D0022808D1002238 +:1023F0001146132000F0E6BA002211461220F9E738 +:102400007047000070EF0120AF0550FA80EF012007 +:1024100038ED00E000071000FD48FE4A01689142D7 +:1024200004D1FD4902794A70002101607047F0B57E +:1024300085B040F24C71F64806F05CFF684605F046 +:10244000F3FEF34C012500266570A680A6710220DC +:10245000E07105F0A6FB208105F09FFB070205F067 +:102460009CFB47EA102060816020208242F26020BD +:102470006082EA480068418AA182018AE182E849D3 +:10248000B1F8FA2E2283B1F8F82E6283427D2277CA +:1024900091F8FC1E6177E3490968497CA177E677EA +:1024A00001992162009961620299A162DDE903123A +:1024B00041EA0221E16281692163C1696163DA490C +:1024C0000968A1630168E163418EA4F85010818E10 +:1024D000A4F8521090F8311004F8541F90F830000E +:1024E0006070D24824F82C0FD1482081D1486081F7 +:1024F000D148A081D148E081D1482082D148608272 +:10250000D148A082D148E082D1482083D14860835D +:10251000D148A083D148E083D1482086D148608645 +:10252000D148A086D148E086D1482087D14860872D +:10253000D148A087D148E087D148A4F85000D148BD +:10254000A4F85200D048A4F85400B349CF48A4F8E6 +:1025500056008888401C8880A52204F8802D65706C +:1025600060800D7005B0F0BD70B5AB4C0546002322 +:10257000A088A749401C82B2A280284601F0FBFC3B +:10258000257070BD70B5054640F24C71A04806F04C +:10259000B1FEA14C9E49A088401C82B2A280284670 +:1025A00001F02AFD257070BD70B59B4C0546207862 +:1025B000A84204D040F24C71954806F09BFEB44806 +:1025C000A5700F2101609248914A1030A0608020D0 +:1025D0001071924802F19005E560006890F83110A2 +:1025E00090F83030517101FB03F005EB4006937118 +:1025F00026610844D17105EB40006061137270BD23 +:1026000070B50546844CC00704D080228749A06875 +:1026100006F0CFFD814EA80712D5316891F8310040 +:1026200091F830104843A178302935D0312935D080 +:10263000322935D08049E3684200184606F0B9FDDA +:10264000680716D53068A17890F831209148302974 +:1026500028D0312931D00078322930D0022838D022 +:10266000052836D0062834D077495200206906F074 +:10267000A0FD280735D5306890F83020A0783028A4 +:1026800029D0312829D0322829D073496069BDE882 +:102690007040520006F08DBD6549CCE76549CAE738 +:1026A0006649C8E70078022805D0052803D0062827 +:1026B00001D06349D9E77349D7E76249D5E70228D2 +:1026C00005D0052803D0062801D06049CDE76F4921 +:1026D000CBE76D49C9E75E49D8E75E49D6E75F4970 +:1026E000D4E770BD4A4AA52010704B4881785170DC +:1026F00001708188491C81805180704730B587B056 +:102700000C4600218DF80C104FF4832504AB03AA6E +:10271000694600F0EBF89DF8100010B1112816D0B2 +:102720001AE09DF80C20BAB10098627105EB8001A7 +:1027300004F110000A78930703D002F0FC0208327B +:1027400000E0121DD2B206F034FD07B030BD3220D9 +:1027500000222071114603E0302000222071114632 +:1027600000F030F9F1E770B505464FF4C87128481C +:1027700006F0C0FD284C2649A088401CA0802846B1 +:10278000FFF7BCFF22482570A52101704570A18884 +:10279000418070BD2DE9F84F884606460C460D1D58 +:1027A00000239B220421404600F06EFD70BBA07800 +:1027B000B0422BD1217800239B22284600F064FDF3 +:1027C0006178884222D1207881070AD0022202EB68 +:1027D0009006002101E02954401CB0EB860FFAD38B +:1027E00002E0012101EB90060024DFF824B04FF451 +:1027F0008325A1464FF0330A55F8240005EB8407E2 +:10280000401C4ED000239B22042145E068E00000DC +:10281000000001204B4355465007100004071000EC +:10282000EC6F012008071000F0FF01009055012017 +:1028300020880120AC410120E847012010560120EA +:102840003C8501205A0C0120D00C0120006F012092 +:1028500066850120840C0120FA0C01202A6F0120DA +:1028600058820120320A0120A80A0120766F012037 +:10287000828201205C0A0120D20A0120A06F01207F +:102880006C810120DE090120080A0120B409012021 +:102890002C071000E8041000384600F0F5FC10B1D9 +:1028A00015E000940CE03878810704EB900401D027 +:1028B000A41C00E0641C602C9ED3B9F1000F06D06C +:1028C00031464046009A05F0A0FA00280CD00022BC +:1028D0008BF804A011463320BDE8F84F00F072B821 +:1028E000002211463120F7E7BDE8F88F2DE9FF5FA0 +:1028F00000260E601D4688464FF48327B1463446B5 +:10290000B3461E7057F8240007EB840A401C23D0FE +:1029100000239B220421504600F0B6FC18B112207F +:10292000287001261CE09AF8022000999AF800000D +:102930008A4208D10299029A4FF001090978491C8C +:102940001170C8F80040810704EB900401D0A41C6A +:1029500000E0641C602CD5D316B9B9F1010F0BD07F +:1029600056EA090606D111202870029981F800B0B4 +:10297000C8F800B0BDE8FF9FD8F80000002307EBBF +:102980008004201D21789B2200F07EFC6178884223 +:1029900002D185F800B0EDE712202870EAE700F0D8 +:1029A00017B838B504466946183000F012FD2046C5 +:1029B000009900F017F838BD0146032000F07CB8FC +:1029C00000F088B800F0A5B800F0B5B800F0BCB8C9 +:1029D0001CB56849D1E90001CDE900016846FFF75F +:1029E000A7FA1CBD1CB5634BD3E90223CDE9002334 +:1029F00090F82421032A1DD0082A21D00B2A1FD0A9 +:102A00009DF8002022F0F00212F120028DF8002043 +:102A100090F8252102F00F02012A17D0022A1BD0BC +:102A2000042A41D0052A9DF8012022F00F0241D04E +:102A3000521C16E09DF8002022F0F0021032E5E76B +:102A40009DF8002022F0F0023032DFE79DF80120EF +:102A500022F00F02921C04E09DF8012022F00F02E8 +:102A6000D21C8DF8012090F833219DF8013062F3DB +:102A700007138DF80130BDF802200B0C63F30B0235 +:102A8000ADF80220BDF8032061F30F12ADF803206A +:102A900030F8441F090A8DF8051000788DF80600FB +:102AA0006846FFF745FA1CBD9DF8012022F00F0291 +:102AB000121DD6E7521DD4E71CB52E4BD3E90423D3 +:102AC000CDE900238DF80100CDF802106846FFF72C +:102AD0002FFA1CBD1CB5284A126892F8A020930753 +:102AE00016D50A2814D2DFE800F0130507070707F8 +:102AF0000707130712060BD51E4BD3E90623CDE9B2 +:102B000000238DF80100CDF802106846FFF710FA97 +:102B10001CBD1CB5174CD4E90834CDE900348DF840 +:102B20000100CDF80210684612B1FFF770FB1CBD22 +:102B3000FFF7FEF91CBD1CB50168009140680190CB +:102B40006846FFF7F5F91CBD1CB54178002910D087 +:102B500005290ED2074AD2E90C12CDE90012D0F8AD +:102B60000210CDF80210C088ADF806006846FFF7E5 +:102B7000DFF91CBD1C970100040710002DE9FF417F +:102B800004F0F2F9234D0024C4EBC40105EB8100ED +:102B900000F10C03027EC8CBCDE90272CDE900360C +:102BA000D0E9012355F82100002104F087FB18B17A +:102BB00021464320FFF7BBFB641C052CE4DB154DCD +:102BC00000248C3505EBC4000021426855F8340020 +:102BD00004F0FBFA18B121464420FFF7A8FB641C5F +:102BE000062CEFDB0B4D002415F1BC05002155F838 +:102BF000240004F050FA18B121464520FFF797FB56 +:102C0000641C042CF2DBBDE8FF8101464620FFF77F +:102C10008EBB00005497010000F01F0301229A4070 +:102C200043099B0003F1E023C3F880224907090E02 +:102C3000002806DA00F00F0000F1E02080F8141DF3 +:102C400003E000F1E02080F80014C3F80021704791 +:102C50002DE9F041642707260025FE4CFE4805F0CB +:102C600086FAFD480368D91C40D04268D11C3DD08B +:102C7000816811F1030F39D0006910F1030F35D0CD +:102C8000B3F1FF3F35D013F1020F32D0B2F1FF3F65 +:102C90002FD012F1020F2CD0B1F1FF3F29D011F14A +:102CA000020F26D0B0F1FF3F23D010F1020F20D049 +:102CB000DFB2D6B2CDB204462A463146384604F0D9 +:102CC00095FF204604F09FFFE44805F026FA03280C +:102CD00014D0012815D0022813D0E048016801293A +:102CE00015D1BDE8F041001D04F089BB002124206E +:102CF00001E000212520FFF767FBDDE70021292007 +:102D000001E000212A20BDE8F041FFF75DBBBDE8EE +:102D1000F0812DE9FC41D24F012501AA69463846D0 +:102D200004F0ECFFCF4C4FF48C56012803D10098EF +:102D3000B0F58C6F04D000212220FFF745FB40E066 +:102D400032463946206806F034FA206804F0E9FF7C +:102D5000012804D000212320FFF736FB002521683D +:102D600028220F46C04801F5865106F022FA41F2AA +:102D7000E6003918BC482022283006F01AFA41F241 +:102D80001C103918B8482822483006F012FA41F2CF +:102D900042103918B4482022703006F00AFA41F285 +:102DA00064003918B0482022903006F002FA41F24F +:102DB0009A003918AC482822B03006F0FAF9002DF4 +:102DC00003D13146206806F073FABDE8FC81F8B5FE +:102DD0000D46064600246A4604F090FF012801D003 +:102DE00001240BE0286831468200A04806F026FA4C +:102DF0009E4804F096FF012800D002242046F8BD2A +:102E0000F8B59A4D9A4F103540F69871994806F0EA +:102E100071FA69463846FFF7DAFF012805D0022823 +:102E200006D0E87801280AD105E00021A02029E099 +:102E30000021A12026E0A87808B9288810B1002137 +:102E4000A2201FE08B48E9880024A0F8F81EA9887A +:102E5000A0F8FA1E297A80F8FC1E0098694607EB54 +:102E600080073846FFF7B3FF78B1012804D000216E +:102E70005FF0A600FFF7A8FAE00728D0A00728D443 +:102E80001121A720FFF7A0FAF8BD6E782946304639 +:102E900000F0F9FF60B1102E0DD0112E0ED0122EC1 +:102EA0000FD0132E10D0182ED7D144F04004D4E701 +:102EB0003146A820DEE744F00104CEE744F00204E6 +:102EC000CBE744F00804C8E744F01004C5E710213C +:102ED000D7E7694920070AD4086890F85022D2073A +:102EE00003D190F88002C00701D01221C9E7E006A3 +:102EF00001D41321C5E76006C6D4086890F85002D3 +:102F0000C007C1D01821BCE730B58DB0EDF776FA17 +:102F10000020012241B201F01F0302FA03F3490924 +:102F2000890001F1E021C1F88031401C1F28F1DB4C +:102F3000EDF762FA04F006FEFFF76EFA05F0CAF943 +:102F400007210A20FFF768FE07210B20FFF764FE28 +:102F5000FEF7C2FFFEF77CFF04A8FFF747F907A8BA +:102F6000FFF77EF804A8009007A802900AA8039033 +:102F7000684605F0C1FB02210020FFF74DFE06F078 +:102F8000C9FA0078C00701D1FEF7C5FFFFF7CAF9FB +:102F9000FFF75EFE04F022FE384D01AA694628467E +:102FA00004F0ACFE344C012802D00021202010E0B7 +:102FB0000098B0F53E7FF8D14FF43E622946206874 +:102FC00006F0F7F8206804F0ACFE012803D00021D9 +:102FD0002120FFF7ACF9FFF79CFE05F045F905004D +:102FE0005DD00121012D02D02E20FFF7A0F920682D +:102FF000017DA94202D02F20FFF799F9FFF700FFCA +:1030000000F052F803F080FC04F0CEF90023012216 +:103010001946052005F0DCFF00231A460121062091 +:1030200005F0D6FF03210120FFF7F6FD042107205C +:10303000FFF7F2FD04210820FFF7EEFD206890F86D +:103040006003C10726D0810724D500214009012350 +:103050001A4615E00090D00328891000508F100008 +:10306000F09F010008071000847F012070641000A9 +:10307000F0BF0100EC6F012004071000F0EF010029 +:10308000009105F0B6F92068002190F8600340092E +:1030900005F037F90DB0BDE83040FFF72BB900213E +:1030A0002D20FFF791F9A9E710B505F0E5FB002306 +:1030B00001221946184605F08BFF0023012219460C +:1030C000104605F085FF00231A460121022005F075 +:1030D0007FFF00231A460121032005F079FF00231A +:1030E0001A460121042005F073FF17480068017C8F +:1030F000A52908D04FF4FA4005F054FF00212820FC +:10310000FFF762F902E0406905F04CFF042102205C +:10311000FFF782FD04210320FFF77EFD042108460E +:10312000FFF77AFD04210520FFF776FD0421062034 +:10313000FFF772FD01210920FFF76EFD0421BDE8B4 +:1031400010400F2068E500000807100070B55A4BCA +:1031500016465C0C08E000BF31F91650A54200DAB3 +:103160002C469D4200DD2B46761EF5D20025002B15 +:1031700001DA1D4609E0002C07DD254605E000BF09 +:1031800031F812305B1B20F81230521EF8D270BD9D +:103190002DE9F047002591460F4680461C462E46F5 +:1031A0005A1E0120294605F0CDFF0BE038F9142006 +:1031B000BA4204DA4A44002A01DD05430E434908B5 +:1031C0004FEA3000641EF1D228463146BDE8F08750 +:1031D0002DE9F047994616461EE0021800F0010559 +:1031E0002A4341EB010707EA010503464F0802EABB +:1031F00003084FEA3004A9F101024FF001004FF03B +:10320000000105F09FFF00EA0800044329400F4336 +:1032100004EA080007EA0501761EDED2D6E78842F6 +:1032200000D30846904200D310467047884200D829 +:103230000846904200D810467047884200D308469E +:103240007047884200D80846704710B500231C46D6 +:1032500042B10278521CD2B202708A4203D9047081 +:10326000012300E00470184610BD30B5002401238E +:1032700005E00C44E41C04F00305641B5B1C934252 +:10328000F7DD00EB440030BD70B50546184600245C +:103290000EE02B5D58400823060602D582EA400066 +:1032A00000E040005B1EC0B213F0FF03F4D1641CC9 +:1032B0008C42EED370BD00000080FFFF30B5B0F946 +:1032C0000240B1F90250641B00D56442B0F900001D +:1032D000B1F90010401A00D54042944203DA9842F6 +:1032E00001DA012030BD002030BD884201DD0846F2 +:1032F00070470028FCDA0020704710B505E000BFD9 +:1033000000EB820353F8044C1C60521EF8D109688C +:10331000016010BD10B503E000EB82030C681C6077 +:10332000521EF9D210BD30B506E000BF00EBC2035B +:1033300073E90245C3E90245521EF7D1D1E90021E4 +:10334000C0E9002130BD10B553884C881B1B438059 +:1033500012880988511A018010BD08B50A46014635 +:103360006846FFF7F0FFBDF90010BDF902004943C0 +:1033700000FB001008BD10B58842029C01DC20460D +:1033800010BD904201DB184610BD8A4200D1521C8C +:10339000401AE31A5843511A90FBF1F0201A10BD5D +:1033A00010B5002A03D0431A934201DD881810BDDE +:1033B0005442A342FBDA881A10BD914201D100B2F7 +:1033C00070475043B0FBF1F000B29042F7D910467D +:1033D000F5E770B50B0002463DD0E64C2068468EFE +:1033E000858EB2F9020031B2FFF77FFF5880B2F943 +:1033F000000029B2FFF779FF1880216891F8361094 +:10340000490702D55988711A5980216891F83610F8 +:10341000890701D5281A1880206890F83610090706 +:1034200010D5B0F83720B3F902003146FFF7C5FFD9 +:10343000588020682946B0F83920B3F90000FFF71A +:10344000BCFF1880206890F83600C00703D0588869 +:1034500019885980188070BD2DE9F047D0F810C048 +:103460000568046A85FB0C12A1FB041242694368DB +:10347000914683FB02628269E246A6FB02677618E8 +:10348000D0E9021781FB07C8C069ACFB00C81CEB80 +:10349000060682FB0A2CA2FB011280FB0902A0FB9C +:1034A0000502401884FB0712A1FB03120818301A0A +:1034B0004FEAE071BDE8F0872DE9FF4F8146AD4846 +:1034C00000268DB000683746B04690F8804390F8EB +:1034D000810300F0030A04B90224BAF1000F01D1FC +:1034E0004FF0040A5FF0000109EBC1004068064498 +:1034F000484300FB0188491C07440629F4DB9E4D24 +:10350000009668680190A868CDE9020728690490D0 +:103510006869CDE90508E8690790286A0890684657 +:10352000FFF79AFF83460B912868CDE90006A8684B +:103530000290E868CDE9030768690590A869CDE9BC +:103540000608286A08906846FFF786FFCDE909015A +:10355000286800906868CDE90106E868039028694A +:10356000CDE90407A8690690E869CDE9070868462F +:10357000FFF772FF06468846DDE90901A0FB043526 +:10358000A6FB047C01FB0451002200FB021508FB92 +:1035900004C106FB0210A7FB04C100FB041007FBDB +:1035A000020013EB0C0345EB00010B9A13EB0B002D +:1035B00051414FF47562002305F0D7FD09EBCA01B4 +:1035C00048600E9948600F990B9AC1E900B2DDE995 +:1035D00009010F9AC2E902010F98C0E904680026A8 +:1035E0003746B0464FEA060059F830100E444143C2 +:1035F00001FB0088401C0F440628F5DB5E4D009659 +:1036000068680190A868CDE9020728690490686994 +:10361000CDE90508E8690790286A08906846FFF731 +:103620001BFFCDE909012868CDE90006A8680290D2 +:10363000E868CDE9030768690590A869CDE906083F +:10364000286A08906846FFF707FFCDE90B01286854 +:1036500000906868CDE90106E86803902869CDE923 +:103660000407A8690690E869CDE907086846FFF7EE +:10367000F3FE80468B46DDE90B01A0FB0453A8FB5B +:10368000046701FB0431002200FB02110BFB0473F1 +:1036900008FB0230A6FB043700FB047006FB0200A7 +:1036A000EB184141DDE90902181851414FF47562E8 +:1036B000002305F05AFD49F83A000E990860DDE94B +:1036C00009021099C1E90002DDE90B01109AC2E973 +:1036D00002011099C1E9048B11B0BDE8F08F2DE90A +:1036E000F05FD1E901651C46A5FB0438D1F80CC098 +:1036F00017460CFB048C0A6882464FF0000B05FB52 +:103700000BC0D318D1E9042104FB04F5A2FB05C8C2 +:1037100001FB058146414FEAE57902FB091213EBF3 +:103720000C0046EB02014FF475625B4605F01DFD8F +:10373000CAF8040097E80B00FA68A3FB04C802FB70 +:10374000048203FB0B2310EB0C025941D7E904342C +:10375000A3FB056704FB057403FB0943901959415A +:103760004FF47562002305F000FDCAF80000BDE8C3 +:10377000F09F0000040710006807100073B51D24B7 +:10378000DDE9005622460120002105F0DBFC28403F +:103790003140084301D1641EF4D50821684604F085 +:1037A0009BFAFF49C0B2096891F8E710C1F34111D3 +:1037B00002290ED310F0030005D0012805D00228FD +:1037C00005D01F200AE00F2008E07F2006E03F2000 +:1037D00004E0C00701D0072000E003200021621CA4 +:1037E00005F0B0FCDDE9002310431943CDE90001E9 +:1037F0007CBD10B5EB4C502818D00ADCA0F11000AD +:1038000009280ED2DFE800F0122828280D0D0D0D32 +:103810002F00512820D052281ED053281CD05828C1 +:1038200021D00020C4E90200014622E003F036F96D +:10383000C4E9020103F034F9C4E90401D84800687E +:1038400090F8E70010F0600F15D0D4E90201FFF7FF +:1038500095FFC4E902010EE003F020F9C4E902017A +:1038600003F01EF905E003F021F9C4E9020103F0B9 +:103870001FF9C4E90401CB480821083004F02CFAF0 +:103880002060C8480821103004F026FA606010BD9E +:103890002DE9FF5F0821DDE90FBA684604F01CFA44 +:1038A0008146082102A804F017FA074600242046A2 +:1038B0003AE042460120002105F044FCDDE9002306 +:1038C0001040194008432DD000252E4627E03246EF +:1038D0000120002105F036FCDDE9022310401940EB +:1038E00008431BD0119860B104FB07F00BEB0501F6 +:1038F0004156324601EB0A0321460E9803F03DFE85 +:103900000BE0324621460E9803F02CFE04FB07F133 +:103910000BEB0502A0EB0A0088546D1C761CBD421F +:10392000D5DB641C08F1010080464C45C1DBBDE8D5 +:10393000FF9F2DE9FF5F84B00821DDE912AB04A8E9 +:1039400004F0CAF98146082106A804F0C5F98046AA +:1039500000250AF1480002902030019048382C469A +:103960002F462E46009034E03A460120002105F013 +:10397000E9FBDDE9042310401940084327D01698DD +:1039800090B11BF8051014980844C2B23946029849 +:1039900003F05FFE05EB090141441BF901203946A4 +:1039A000504603F02EFE10E03946029803F04FFE19 +:1039B0001499401A0BF805003946504603F01AFED8 +:1039C00005EB090242440BF802006D1CEDB27F1CAE +:1039D000FFB24D45C8DB38E032460120002105F03A +:1039E000B1FBDDE906231040194008432BD016989F +:1039F000A0B104EB090115981BF801100844C2B2EC +:103A00003146019803F025FE04EB490141441BF9BE +:103A100001203146009803F0F4FD12E03146019890 +:103A200003F015FE159904EB0902401A0BF8020089 +:103A30003146009803F0DEFD04EB490242440BF8E6 +:103A40000200641CE4B2761CF6B24445C4DB08B044 +:103A5000BDE8F09F2DE9FF5F0821DDE90EBA684659 +:103A600004F03AF98146082102A804F035F9074626 +:103A70000024204629E042460120002105F062FB97 +:103A8000DDE900231040194008431CD000252E46D4 +:103A900016E032460120002105F054FBDDE9022347 +:103AA0001040194008430AD032462146584603F0D8 +:103AB00059FD04FB075280002AF812006D1C761C89 +:103AC000BD42E6DB641C08F1010080464C45D2DBB8 +:103AD0002DE72DE9FF5F0821DDE90E9B684604F024 +:103AE000FBF88246082102A804F0F6F8002580467B +:103AF0002C462F462E463DE03A460120002105F097 +:103B000021FBDDE9002310401940084330D039463D +:103B100009F1480003F09BFD214999F892C00A6819 +:103B200092F8413192F8402103F00F01491C0CFB3F +:103B300001FC012101EB131300FB03C399F8900072 +:103B400001EB121100FB0130109919B94FF6FF710A +:103B500001EA80002BF815003946484603F04AFD7B +:103B600005EB0A02800042446D1C2BF81200EDB2F6 +:103B70007F1CFFB25545BFDB44E0324601200021E7 +:103B800005F0E0FADDE9022310401940084337D080 +:103B9000314609F1680003F05AFD99F8935003E0AB +:103BA0000407100090071000F9490B6893F84311BF +:103BB00093F8423101F00F02521C5543012202EBEF +:103BC000111100FB015199F8910002EB131200FB57 +:103BD0000210109919B94FF6FF7101EA800004EB49 +:103BE0000A0231462BF8120009F1200003F002FD11 +:103BF00004EB4A0280004244641C2BF81200E4B239 +:103C0000761CF6B24445B8DB91E62DE9FF5F08214A +:103C1000DDE90E9B684604F05FF88246082102A8A1 +:103C200004F05AF8002580462C462F462E463DE0EB +:103C30003A460120002105F085FADDE90023104015 +:103C40001940084330D0394609F1480003F0FFFC21 +:103C5000CF4999F892C00A6892F8F93A92F8F82A8E +:103C600003F00F01491C0CFB01FC012101EB1313B4 +:103C700000FB03C399F8900001EB121100FB013027 +:103C8000109919B94FF6FF7101EA80002BF8150061 +:103C90003946484603F0AEFC05EB0A028000424478 +:103CA0006D1C2BF81200EDB27F1CFFB25545BFDB37 +:103CB0003FE032460120002105F044FADDE902230D +:103CC00010401940084332D0314609F1680003F032 +:103CD000BEFCAF4999F893500B6893F8FB1A93F820 +:103CE000FA3A01F00F02521C5543012202EB111166 +:103CF00000FB015199F8910002EB131200FB021036 +:103D0000109919B94FF6FF7101EA800004EB0A021D +:103D100031462BF8120009F1200003F06BFC04EB94 +:103D20004A0280004244641C2BF81200E4B2761C64 +:103D3000F6B24445BDDBFAE52DE9F043894600279C +:103D400087B0904604463E46FC2105F0B1FA914DFD +:103D5000B8F1010F28782071287960718E4890F8A9 +:103D6000821BA17190F8831BE17190F8841BA172F2 +:103D700090F8851BE17290F8801B217390F8810BFD +:103D8000607308D185480068817FA52903D190F927 +:103D90001F7090F920607E480021006890F834017F +:103DA000CDE9027600F00100CDE9041004F1100025 +:103DB0007B49CDE9001005F108000FC8FFF7B9FDF8 +:103DC000A520207012206070A4F80290D5E90001AF +:103DD0000844132101EB4000800807B0BDE8F083E0 +:103DE0002DE9F0438946002787B0904604463E46B9 +:103DF000FC2105F05DFA674DB8F1010F28782071BC +:103E000028796071644890F81A1CA17190F81B1C05 +:103E1000E17190F81C1CA17290F81D1CE17290F8E1 +:103E2000181C217390F8190C607309D15B48006865 +:103E300090F82110A52903D110F9227F90F9016093 +:103E400053480021006890F8E009CDE9027600F0BF +:103E50000100CDE90410524904F110009831CDE978 +:103E6000001005F108000FC8FFF763FDA5202070C2 +:103E700013206070A4F80290D5E90012114400EB01 +:103E800041008008A9E770B50E4605460024FFF7FB +:103E9000B0FC103D092D0ED2DFE805F005090F1327 +:103EA0000D0D0D0D1700304600F00CF902E0304604 +:103EB00000F02BF90446204670BD304600F047F96B +:103EC000F8E7304600F084F9F4E7304600F025FAD0 +:103ED000F0E72DE9F0438946002787B09046044675 +:103EE0003E46FC2105F0E4F92A4DB8F1010F28788F +:103EF000207128796071284890F8921FA17190F87C +:103F0000931FE17190F8941FA17290F8951FE172D0 +:103F100090F8901F217390F8910F607308D11F489B +:103F20000068817FA52903D110F92A7F90F90160EB +:103F300017480021006890F8EC0ACDE9027600F0FD +:103F40000100CDE9041004F110001649CDE900107C +:103F500005F108000FC8FFF7ECFCA5202070182021 +:103F60006070A4F80290D5E900010844132101EB28 +:103F70004000800831E72DE9F0411E46174688468B +:103F800005460024FFF735FC103D092D1FD20BE03C +:103F90000407100090071000EC6F012008071000C4 +:103FA000DC7A0120EC7E0120DFE805F0050B141A15 +:103FB00011111111200032463946404600F04AF9ED +:103FC00004E032463946404600F076F90446204681 +:103FD000BDE8F081324639464046FFF7ADFEF5E7D1 +:103FE000324639464046FFF7FBFEEFE73246394698 +:103FF0004046FFF76EFFE9E72DE9FF411746064609 +:104000000D46FFF7F6FBE548A6F1500205F1100456 +:104010000178297101796971E149092A4CD2DFE8F7 +:1040200002F00507121F4B4B4B4B3600DD4900E0F9 +:10403000DD49CDE9001484680C3090E80E0020467C +:10404000FFF708FD38E00968D84B91F8342191F862 +:10405000401102F0010201F00101CDE902120CE071 +:104060000968D24B91F8E02991F8EC1902F00102AD +:1040700001F00101CDE902129833CDE900348468E2 +:104080000C3090E80E002046FFF723FD14E009688D +:10409000C74B91F8EC2A91F8F81A02F0010201F0EE +:1040A0000101CDE90212CDE9003484680C3090E8BA +:1040B0000E002046FFF7A9FDA52028706E706F80C6 +:1040C000BDE8FF811FB5B54902790B689A4203D15B +:1040D00042794B689A4202D0002004B010BDB54B23 +:1040E00000221B689C7EA52C01D193F91B20AD4CAE +:1040F0000DF1040C0123103000948CE80D00083100 +:104100000FC9FFF7C5FB0120E7E71FB5A3490279F7 +:104110000B689A4203D142794B689A4201D0002041 +:10412000DBE7A44B00221B681C7FA52C01D193F96F +:104130001D209D4B0DF1040C0124103000938CE8E0 +:10414000150008310FC9FFF7A3FB0120C5E730B503 +:104150009249027987B00B689A4203D142794B6841 +:104160009A4202D0002007B030BD8E4A85790024E3 +:1041700082F8825BC57982F8835B857A82F8845BFA +:10418000C57A82F8855B057B82F8805B457B82F887 +:10419000815B884A23461268957FA52D03D192F949 +:1041A0001F4092F920307E4A0125103012680831F4 +:1041B00092F83421CDE9024302F00102CDE9045224 +:1041C0007A4ACDE900200FC9FFF7B3FB0120CAE707 +:1041D00030B57249027987B00B689A4203D14279AF +:1041E0004B689A4201D00020BDE76E4A85790024D1 +:1041F00082F81A5CC57982F81B5C857A82F81C5CAF +:10420000C57A82F81D5C057B82F8185C457B82F8D4 +:10421000195C684A2346126892F82150A52D03D1F3 +:1042200012F9224F92F901305D4A012510301268CF +:10423000083192F8E029CDE9024302F00102CDE90C +:1042400004525A4A9832CDE900200FC9FFF771FB9A +:10425000012088E72DE9FF410F4615460446002658 +:1042600040F27A3105F024F84C48012D0178217193 +:104270000179617106D14F4909688A7EA52A01D169 +:1042800091F91B6004F11001464BCDE90031002289 +:10429000CDE9026200F1080105460FC9FFF7F8FAFF +:1042A000A5202070102060706780D5E90001484388 +:1042B0001330800804B08BE62DE9FF410F46154608 +:1042C0000446002640F27A3104F0F2FF3348012D13 +:1042D000017821710179617106D1364909680A7F37 +:1042E000A52A01D191F91D6004F110012E4ACDE9F2 +:1042F00000210023CDE9026300F1080105460FC942 +:10430000FFF7C6FAA5202070112060706780D5E9FC +:104310000001484313308008CCE730B51F490279CB +:1043200087B00B689A4203D142794B689A4201D018 +:10433000002018E71B4A8579002482F8925FC5792E +:1043400082F8935F857A82F8945FC57A82F8955FE8 +:10435000057B82F8905F457B82F8915F154A234682 +:104360001268957FA52D03D112F92A4F92F90130D9 +:104370000B4A012510301268083192F8EC2ACDE979 +:10438000024302F00102CDE90452094ACDE90020BE +:104390000FC9FFF7CEFA0120E5E6000090071000F4 +:1043A00004071000EC6F012014750120DC7A012055 +:1043B000EC7E0120080710002DE9F04F47F6FF774B +:1043C000DDE909B58146FE4301209A4684462C4624 +:1043D00015E000BF32F8143031F81480A3EB080365 +:1043E0001BB2BB4200DA1F46B34200DD1E46002B63 +:1043F00002DD4FF0000C02E001DA4FF00000641E15 +:10440000E8D220B1BCF1000F01D0002309E050EA4E +:104410000C0306D020B9BCF1000F01D0334600E0F8 +:104420003B4600273C462846CBF1000C0EE000BF7F +:1044300032F8106031F81080A6EB0806F61A36B292 +:10444000564503DA664501DD3744641C401EEFD251 +:1044500004B9012497FBF4F0184404E031F8152066 +:10446000024429F815206D1EF8D2BDE8F08FF0B592 +:10447000002306461D4618460EE000BF36F91140DF +:10448000002C01DB274600E06742974204DD002C48 +:1044900001DD254400E02344491EEFD2002B00DA61 +:1044A0005B42AB4200DD0120F0BDF0B5724D6F42C2 +:1044B0006E0C0EE032F9134031F913C0A4EB0C047A +:1044C000BC4201DB344602E0AC4200DA2C4620F864 +:1044D00013405B1EEED2F0BD70B5049C09E000BF36 +:1044E00031F9145032F91460754395FBF3F520F857 +:1044F0001450641EF4D270BDF0B4049C1CB913B106 +:10450000C3F110040EE0F0BC520004F052BE00BF34 +:1045100030F9125031F912605D4306FB04552D113C +:1045200020F81250521EF3D2F0BC7047F0B4049C35 +:104530001CB913B1C3F180040EE0F0BC520004F0CA +:1045400038BE00BF30F9125031F912605D4306FBEE +:104550000455ED1120F81250521EF3D2E4E7F0B5E5 +:10456000002B19D0144615E000273E46E51A04EB4F +:10457000030C08E0002D05DB954203DA31F915E064 +:10458000761C77446D1CAC45F4DA1EB197FBF6F54A +:1045900020F81450641EE7D2F0BD70B50C461546E5 +:1045A000A04204D001466A00204604F002FE00202A +:1045B00017E00146421C07E034F9126034F911306B +:1045C0009E4200DA1146521CAA42F5D3884207D017 +:1045D00034F8102034F8113024F8103024F8112069 +:1045E000401CB0EB550FE4D9E90725F0010001D0DC +:1045F000205E70BD215E204430F9020C084440105A +:1046000070BD0346002004E033F91120824200DD32 +:104610001046491EF8D2704710B5002447F6FF73C4 +:1046200008E000BF30F91120A24200DD14469A4292 +:1046300000DA1346491EF5D2E01A00B210BD034657 +:1046400047F6FF7005E000BF33F91120824200DA1F +:104650001046491EF8D2002800DA002070470246B2 +:10466000B0F9000005E000BF32F91130834200DDEF +:104670001846491EF8D270470080FFFF70B505004C +:1046800003D0BDE8704002F0EFB9FE4C21466078DF +:10469000097930B10A46FC4901F1980002F036FA76 +:1046A0000BE0207802F000FB21794A00F64901EB8B +:1046B0004001F548983004F07CFDA078F34E28B115 +:1046C000F1482179983002F0EDFA01E0EE48983097 +:1046D000B062E07886F831002846D2E72DE9F05F35 +:1046E000DFF8ACA383460127DAF80000B84600F2F1 +:1046F0005E6490F8F41990F8F05901F01F0690F8F4 +:10470000F11901F00F0990F8DE19890609D590F822 +:10471000581690F859060A2204EB400002F032FACB +:104720000746DAF8000090F8DE19490609D590F836 +:10473000D21890F8D3080A2204EB400002F022FAC3 +:1047400080464FF48070854200D905461F2E00D95F +:104750001F26761C754309F101004543C5EB452032 +:104760007843DAF8002000FB08F0C01392F8871AAB +:10477000B0FA80F0C0F12000890611D50021BBF10C +:10478000010F06D192F88D1A0A0701F0070100D532 +:104790004942401801D5002002E01F2800DD1F20FB +:1047A000C0B2BDE8F09FF8B5044602F016FEB64868 +:1047B00002F018FEA4F8760002F0CEF9B14A0B46DA +:1047C000127800920246204603F0E1F802F0C9F99F +:1047D00002460B46204603F010F9204602F082FA0A +:1047E000AB4DB4F856102868B0F8C02062F3090148 +:1047F000A4F8561090F8BF0094F8551060F3030128 +:1048000084F855100521204602F017FE286890F81C +:10481000F009A0702868218EB0F8F62962F308012B +:10482000218690F8F10900F00F01204602F07CFE8D +:10483000286834F81A1FB0F8E82962F30B0124F84D +:104840001419B0F8E629618962F30B016181B0F8AF +:10485000E419E08861F30B00E08014F8050C20F007 +:104860000C0004F8050C2868217B90F8F22962F30B +:104870000101217390F8F229920862F387112173E4 +:1048800090F8DE19627861F30002627090F8E10935 +:10489000E070804890F8181C217690F8191CA177D8 +:1048A00090F81A1C617690F81B1CE17790F81C1C9C +:1048B000A17690F81D0C84F82000774802F092FD54 +:1048C000A4F87A007448203002F08CFDA4F87E0031 +:1048D000286814F8166F90F8EC19090961F30716A7 +:1048E00004F8066B90F8EE192278090961F30712B3 +:1048F000227090F8ED3914F8051C63F3030104F8F5 +:10490000051C90F8EF79637867F30303637090F800 +:10491000ED793F0967F3071104F8051C90F8EF19CA +:10492000090961F30713637090F8EC1961F300064D +:1049300004F8066C90F8EE1961F3000204F82229DD +:1049400090F8E2090109204602F0FAFD5248483881 +:1049500002F048FDA4F87E004F482734283802F0C2 +:1049600041FDA4F85B00296891F8E00982082078ED +:1049700062F38300207091F8E02962F30000207058 +:1049800091F8E029520862F3410004F8010B207805 +:1049900020F01000207091F8DE29D308E27A63F34A +:1049A0004512E27291F8DF1961F3451004F8280905 +:1049B000204602F069F9286890F8DF09C0F3410148 +:1049C000204602F08BFD296891F8DE09820914F86F +:1049D000330F62F3000004F81D0991F8DE29520933 +:1049E00062F34100607791F8F309E27D60F304021D +:1049F000E27591F8F419A07D61F30400A0752248D6 +:104A000094F849100838407860F30401224884F88B +:104A10004910E83002F0E6FCA4F86400286834F895 +:104A2000181FB0F8EA2962F30B0124F8041910F8F2 +:104A3000E31F227861F3030204F8012B01780A09CD +:104A4000217862F3030104F8091B90F8FB18CA09E6 +:104A5000217862F3000104F82B1B14F8571941F078 +:104A6000200184F8571090F810194A09217862F350 +:104A70000611217090F8FC184A09217C62F3C301E9 +:104A800021740BE0A8071000D4800120108F1000C3 +:104A900004071000EC6F0120BC7B012090F8FB089C +:104AA000400860F304112174F8BD2DE9F04104467B +:104AB000524D01200129A87008D00026504F02292C +:104AC00008D0032914D004292CD13AE0204600F064 +:104AD00091F827E04B48FFF766FE204600F08AF881 +:104AE000B87894F85F1060F3040184F85F1014E064 +:104AF0004448FFF758FE204600F07CF8F87894F818 +:104B00005F1060F3040184F85F1094F8270020F030 +:104B1000020040F0010084F827000021204602F046 +:104B200003FDAE7094F8270040F30000401CE870CD +:104B30003548006890F8DF09C0F380106870BDE860 +:104B4000F081204600F056F8204602F00CF9E8E724 +:104B50007CB502F001F8CDE900010821684603F0B8 +:104B6000BBF82649264D08710020286028710124D1 +:104B7000E0B2FFF7B3FD2855641C052CF8DB214893 +:104B8000FFF711FE7CBD30B5017AA9B079B3684654 +:104B9000FFF78BFF9DF8120000F0030002F044F8CD +:104BA000194C206800F25E6300F6D80590F858169C +:104BB00090F8590603EB400002F007F8206890F8DF +:104BC000D21890F8D30805EB400002F015F80B4816 +:104BD000417801B102210170C9B2684602F027FF95 +:104BE0000A49684602F058FF002029B030BDFFE7AF +:104BF0000120FAE7A422034904F0DBBAA807100059 +:104C0000CC8001203C891000040710002D460100D3 +:104C1000FE49C868401CC860022803D2FC4951F80C +:104C200020000047002001F01FBF002801D102F042 +:104C300024BF7047F54910B50A790120521CD2B241 +:104C40000A710B7A9A420AD8487A48B102F066FE95 +:104C50000320EBF7D5FBEF4802F054FE002010BD17 +:104C600002F00BFFFAE770B514460E46054653B93D +:104C7000A10004F03FFB06E055F8240036F91410BB +:104C8000084445F82400641EF6D270BD70B5E24CAD +:104C90006642650C0BE000BF51F82230B34201DBE5 +:104CA0002B4602E0A34200DA234620F81230521EBF +:104CB000F2D270BD70B518B1BDE8704001F0D4BE3D +:104CC000D24C207A08B1D54D01E0D44D763DCF4984 +:104CD0006079897801282FD0022833D0607801F0DC +:104CE000E3FFA178C0B24A00CD4901EB400128465C +:104CF00004F05FFAC9482379A27829464E30FFF7BD +:104D0000B2FFFFF797FF002825D0C449A2784E31A3 +:104D1000A1F1C400FFF7BAFFA079C24D012814D059 +:104D2000BE4876386863E07985F83E00207985F8DA +:104D30003C00BDE870406BE70A46B949284601F0DF +:104D4000E5FED7E74A00B649D1E7B448A1787638FE +:104D500001F0A8FFE6E770BD70B518B1BDE870407E +:104D600001F082BEA94C207A08B1AC4D01E0AB4DF8 +:104D70004C3DA6496079C97801282FD0022833D04C +:104D8000607801F097FFE178C0B24A00A44901EBD6 +:104D90004001284604F00DFAA0482379E27829461C +:104DA0004E30FFF760FFFFF745FF002825D09B49F5 +:104DB000E2784E31A1F19A00FFF768FFA079994D92 +:104DC000012814D095484C38A863E07985F83E0056 +:104DD000207985F83D00BDE8704019E70A46904902 +:104DE000284601F093FED7E74A008D49D1E78B486A +:104DF000E1784C3801F057FFE6E770BD2DE9F14F3F +:104E0000DFF824B20127B846DBF8000000F25E6448 +:104E100090F8001B90F801AB01F01F0690F8FD1A06 +:104E200090F8FC5A01F00F0990F8EA1A890609D5A2 +:104E300090F85A16B0F85B060A2204EB400001F025 +:104E4000A1FE0746DBF8000090F8EA1A490609D5EA +:104E500090F8D41890F8D5080A2204EB400001F02D +:104E600091FE80464FF48070854200D905461F2E82 +:104E700000D91F26761C754309F101004543C5EB97 +:104E80004520784300FB08F00AF101014843DBF8B4 +:104E90000020C013B0FA80F092F8871AC0F1200009 +:104EA00009061FD5009B0021012B06D0022B0FD035 +:104EB000032B0DD0042B07D10AE092F8E81A0A0759 +:104EC00001F0070100D54942401808D5002009E04B +:104ED00092F8E81A0A06C1F30211F4D4F4E71F2885 +:104EE00000DD1F20C0B2BDE8F88FF8B5044602F01F +:104EF00074FA4B4802F076FAA4F8760001F02CFE22 +:104F0000424E0B46727800920246204602F03FFD68 +:104F100001F027FE02460B46204602F06EFD2046B9 +:104F200001F0E0FE404DB4F856102868B0F8D72ADA +:104F300062F30901A4F8561090F8D60A94F85510B7 +:104F400060F3030184F855100521204602F075FA3C +:104F5000286890F8FC0AA0702868218EB0F8022B0F +:104F600062F30801218690F8FD0A00F00F01204647 +:104F700002F0DAFA286834F81A1FB0F8F42A62F35B +:104F80000B0124F81219B0F8F22A218962F30B01FF +:104F90002181B0F8F02AA18862F30B01A18090F87A +:104FA000FE2AA17A62F30101A17290F8FE2A92080A +:104FB00062F38711A17290F8EA1A14F8012C61F3D8 +:104FC000000204F8012C90F8ED0A6070174890F880 +:104FD000901FA17590F8911F217790F8921FE175AD +:104FE00090F8931F617790F8941F217690F8950FB1 +:104FF000A0770F4802F0F6F9A4F878000C482030AA +:1050000002F0F0F9A4F87C00286813E0B007100063 +:1050100020980100DB4B01000080FFFFCE820120C1 +:10502000C0810120108F100004071000EC6F0120D8 +:10503000347F012090F8F81A14F8147F090961F3FD +:10504000071704F8067B90F8FA1A0A09217862F328 +:105050000711217090F8F93A14F8052C63F3030254 +:1050600004F8052C90F8FBCA63786CF303036370B3 +:1050700090F8F9CA4FEA1C1C6CF3071204F8052CCF +:1050800090F8FB2A120962F30713637090F8F82A6C +:1050900062F3000704F8067C90F8FA2A62F3000134 +:1050A00004F8221990F8EE0A0109204602F048FAA5 +:1050B000D74802F097F9A4F87E00D548273420306D +:1050C00002F090F9A4F85B00296891F8EC0A8208D4 +:1050D000207862F38300207091F8EC2A62F30000DC +:1050E000207091F8EC2A520862F3410004F8010B99 +:1050F000207820F01000207091F8EA2AD308E27A94 +:1051000063F34512E27291F8EB1A61F3451004F86B +:105110002809204601F0D4FD286890F8EB0AC0F376 +:105120004101204602F0DAF9286890F8EA1A8A0963 +:1051300014F8331F62F3000104F8071990F8EA2A03 +:10514000520962F34101E17190F8FF1A627861F34C +:105150000402627090F8000B217860F30401AD48FE +:10516000217094F83310407860F3040184F8331010 +:10517000A94802F037F9A4F84E00286834F8021F55 +:10518000B0F8F62A62F30B0124F8181910F8E31F9F +:10519000227D61F30302227501780A09617D62F3C1 +:1051A0000301617590F8071ACA09A17F62F3000133 +:1051B000A17794F8491041F0200184F8491090F843 +:1051C0001D1A4A0914F80E1C62F3061104F80E1C8D +:1051D00090F8081A4A09A17862F3C301A17090F807 +:1051E000072A520862F30411A17090F8080A800996 +:1051F0007071F8BDA422894903F0DBBF2DE9F041AD +:10520000874D002601272E71AF712E720C466E72EB +:10521000012807D07F4F02282AD0032812D0042863 +:1052200038D13FE00846FFF7E5FF7E48016891F876 +:10523000EF0A42062ED591F8011B2972000629D5E6 +:105240006F7227E07548FFF750FE2046FFF7D2FF48 +:10525000F87894F85F1060F3040184F85F1094F814 +:10526000270020F0020040F0010084F827000CE045 +:105270006A48FFF73AFE2046FFF7BCFFB87894F87B +:105280005F1060F3040184F85F100021204602F0F3 +:105290004BF9AE7194F8270040F30000401CE87110 +:1052A000BDE8F0810846FFF7A5FF204601F05BFD51 +:1052B000EFE770B55B4D286800F25E6200F6D80437 +:1052C00090F85A16B0F85B0602EB400001F07DFC46 +:1052D000286890F8D41890F8D50804EB4000BDE891 +:1052E000704001F089BC70B54D4D4C4C6879A434C8 +:1052F000012826D0022826D0002068702146287870 +:10530000FFF77CFF47480168A07C91F8FE2A62F312 +:105310000100A07491F8FE1A890861F38710A07447 +:105320006978204602F083FBA07C00F0030001F0C6 +:105330007BFCFFF7BEFF2046BDE870403A4902F013 +:10534000ABBB0220D9E70820D7E770B5344D334C0A +:105350006879A434012827D0022827D0012068705A +:1053600021462878FFF74AFF2E48016891F8FE0A87 +:105370000209A07C62F30100A07491F8FE1A890969 +:1053800061F38710A0746978204602F050FBA07C7E +:1053900000F0030001F048FCFFF78BFF2046BDE85A +:1053A0007040224902F078BB0320D8E70920D6E7F5 +:1053B0007FB501F0D1FBCDE9000101F0D2FBCDE9D1 +:1053C00002010821684602F087FC154C0821A070F4 +:1053D00002A802F081FCE0700E4D0124E0B2FFF75C +:1053E0000DFD2855641C052CF8DB0C48FFF77DFDEE +:1053F0007FBD10B5C07A40B1094908704FF0FF3049 +:10540000C860FFF705FC002010BD012010BD0000A2 +:10541000EC7E0120B8810120A47C0120E0891000ED +:10542000B007100004071000654C0100094D010091 +:1054300010B5040003D0BDE8104001F015BB2548AD +:1054400025490078420001EB40012348983003F0E1 +:10545000B0FE21482149983048622046EBE71CB550 +:1054600001F07AFBCDE900010821684602F034FC26 +:1054700018491B4C0870204600F0D5FA164801F078 +:10548000B1FFA4F8760017480168A07C91F8462186 +:1054900062F30100A07491F84611890861F3871046 +:1054A000A0741CBD10B50E4CC07980B1A07C00F07A +:1054B000030001F0B9FB00F008FB0421204602F0D4 +:1054C000B6FA0949204602F0E7FA002010BD012093 +:1054D00010BD0000C0071000B4830120108F100021 +:1054E000288B100004071000E1530100FE49C86832 +:1054F000401CC860022803D2FC4951F82000004734 +:10550000002001F0B1BA002801D102F0B6BA70470C +:10551000F54910B50A790120521CD2B20A710B7AF2 +:105520009A420AD8487A48B102F0F8F90320EAF71B +:1055300067FFEF4802F0E6F9002010BD02F09DFA87 +:10554000FAE770B518B1BDE8704001F08DBAE64CCD +:10555000207A08B1E74D01E0E64D763DA078E649B6 +:10556000820001F5AE7003F069FE607928B1A2787F +:10557000E149284601F0CAFA0CE0A178607801F010 +:1055800093FBA178C0B24A00DB4901EB40012846F9 +:1055900003F00FFED7482379A2782946763801F028 +:1055A000C6FAFFF7B5FF002815D0A079D34D012822 +:1055B0000BD0D0487638A861E07985F830002079A2 +:1055C00085F82000BDE8704090E7CA48A178763899 +:1055D00001F068FBEFE770BD70B518B1BDE8704031 +:1055E00001F042BAC04C207A08B1C24D01E0C14D71 +:1055F0004C3DE078C049820001F5D87003F01EFEF2 +:10560000607928B1E278BC49284601F07FFA0CE0C5 +:10561000E178607801F04EFBE178C0B24A00B6490B +:1056200001EB4001284603F0C4FDB2482379E2783B +:1056300029464C3801F07BFAFFF76AFF002815D0A5 +:10564000A079AE4D01280BD0AA484C38E861E0792A +:1056500085F83000207985F82100BDE8704045E7E5 +:10566000A448E1784C3801F01EFBEFE770BD2DE94E +:10567000FF5FDFF88CB28C460127DBF80000109E3C +:10568000134690F8491190F8444101F0030A90F84C +:105690004811B84601F01F0590F8451190F8320105 +:1056A00001F00F09800605D50A221946604601F06F +:1056B00069FA0746DBF8000090F83201400605D58C +:1056C0000A220E99039801F05DFA80464FF480702B +:1056D000844200D904461F2D00D91F256D1C6C4340 +:1056E00009F101004443C4EB4420784300FB08F077 +:1056F0000AF101014843DBF80010C013B0FA80F052 +:1057000091F8871AC0F12000C9060FD5009A002130 +:10571000012A04D10F9909B1714200E031464018C5 +:1057200001D5002002E01F2800DD1F2004B0C0B218 +:10573000BDE8F09FF8B5044601F04FFE6E4801F059 +:1057400051FEA4F8760001F007FA674E0B46727816 +:1057500000920246204602F01AF901F002FA0246CF +:105760000B46204602F049F9204601F0BBFA644D91 +:10577000B4F856102868B0F8C02062F30901A4F804 +:10578000561090F8BF0094F8551060F3030184F8A8 +:1057900055100521204601F050FE286890F844017C +:1057A000A0702868218EB0F84A2162F30801218692 +:1057B00090F8450100F00F01204601F0B5FE286881 +:1057C00034F81A1FB0F83C2162F30B0124F81219C7 +:1057D000B0F83A21218962F30B012181B0F8382118 +:1057E000A18862F30B01A18090F84621A17A62F3AF +:1057F0000101A17290F84621920862F38711A1720B +:1058000090F8321114F8012C61F3000204F8012C15 +:1058100090F8350160703B4890F8801BA17590F8B6 +:10582000811B217790F8821BE17590F8831B6177CB +:1058300090F8841B217690F8850BA077324801F010 +:10584000D1FDA4F878003048203001F0CBFDA4F859 +:105850007C00286890F840110A0914F8141F62F3BC +:10586000071104F8061B90F842211309227863F30C +:105870000712227090F8417114F8053C67F3030396 +:1058800004F8053C90F843C167786CF30307677030 +:1058900090F841C14FEA1C1C6CF3071304F8053C57 +:1058A00090F843311B0963F30717677090F8403194 +:1058B00063F3000104F8061C90F8421161F3000242 +:1058C00004F8222990F836010109204601F038FE3B +:1058D0000D48483801F086FDA4F87E000A482734B8 +:1058E000283801F07FFD11E0C4071000289801005E +:1058F000B7540100B2850120A4840120108F10004C +:1059000004071000EC6F0120247B0120A4F85B0049 +:10591000296891F834018208207862F383002070AE +:1059200091F8342162F30000207091F8342152087C +:1059300062F3410004F8010B207820F01000207081 +:1059400091F83221D308E27A63F34512E27291F8BA +:10595000331161F3451004F82809204601F082F95B +:10596000286890F83301C0F34101204601F0B6FDEC +:10597000286890F832118A0914F8331F62F3000185 +:1059800004F8071990F83221520962F34101E171DC +:1059900090F84711627861F30402627090F8480150 +:1059A000217860F304012170CC4801F01BFDA4F8BC +:1059B0004E00286834F8021FB0F83E2162F30B0154 +:1059C00024F8181910F8E31F227D61F303022275F1 +:1059D00010F8451B0A09617D62F303016175817A44 +:1059E000CA09A17F62F30001A17794F8491041F040 +:1059F000200184F84910C17F4A0914F80E1C62F393 +:105A0000061104F80E1CC17A4A09A17862F3C30199 +:105A1000A170827A520862F30411A170C07AC0F3B7 +:105A200080107071F8BDA422AD4903F0C2BB2DE90E +:105A3000F041AC4C002601272671A77126720D4655 +:105A40006672012806D0022825D0032814D0042825 +:105A50002CD133E00846FFF7E6FFA348016891F830 +:105A60003701420622D591F84911000601F00301E1 +:105A700021721BD5677219E09948FFF75BFE284633 +:105A8000FFF7D1FF95F8270020F0020040F0010059 +:105A900085F8270005E09248FFF74CFE2846FFF7FF +:105AA000C2FF0021284601F03FFDA67195F82700AE +:105AB00040F30000401CE071BDE8F0810846FFF7AC +:105AC000B2FF284601F04FF9EFE770B5864D286820 +:105AD00000F25E6200F6D80490F8541690F855066D +:105AE00002EB400001F071F8286890F8CE1890F8A9 +:105AF000CF0804EB4000BDE8704001F07DB870B500 +:105B0000794D286800F25E6200F6D80490F85616C7 +:105B100090F8570602EB400001F057F8286890F81B +:105B2000D01890F8D10804EB4000BDE8704001F0B7 +:105B300063B870B56B4D6A4C6879A43400B102202B +:105B4000687021462878FFF772FF674928780A684D +:105B5000A17C92F8463163F30101A17492F84621C9 +:105B6000920862F38711A1746049085C94F85F1091 +:105B700060F3040184F85F106978204601F057FF54 +:105B8000A07C00F0030001F04FF8FFF79EFF2046D5 +:105B9000BDE87040564901F07FBF70B5514D504C83 +:105BA0006879A43408B1032000E001206870214620 +:105BB0002878FFF73CFF4C4928780A6892F846118C +:105BC0000B09A17C63F30101A17492F846219209AB +:105BD00062F38711A1744549491D085C94F85F1070 +:105BE00060F3040184F85F106978204601F01FFF1C +:105BF000A07C00F0030001F017F8FFF780FF2046BB +:105C0000BDE870403B4901F047BF2DE9F041364EF9 +:105C100088B0356805F25E6500F09EFFCDE90401AD +:105C200000F09FFFCDE90601082104A802F054F816 +:105C30002C4C0821A07006A802F04EF82B4FE07003 +:105C4000012407F10508306890F88C1A90F8CE38D6 +:105C500001F00702C1F3C0010093CDE9011290F8F1 +:105C6000CF1890F8542690F8550605EB410305EB44 +:105C70004001E0B2FFF7FBFC3855306890F88C1A11 +:105C800090F8D038C1F30212C9090093CDE901128E +:105C900090F8D11890F8562690F8570605EB410376 +:105CA00005EB4001E0B2FFF7E2FC08F80400641CD9 +:105CB000052CC8DB0A48FFF73DFD08B0FCE610B52F +:105CC000807940B1074908704FF0FF30C860FFF796 +:105CD0000DFC002010BD012010BD0000A47C01209F +:105CE000CC8B1000C407100004071000988401201A +:105CF000F35401008955010010B9714A6F491161CF +:105D000000F0B2BE70B56F4D0446286890F8F101FE +:105D1000C0F30112C0F3810100F00300FDF786FA21 +:105D2000401CC6B2204600F033FC644801F05AFB28 +:105D3000A4F8760000223146204601F059FDA079F2 +:105D400040F00200A07194F86F0066F3020084F83E +:105D50006F0094F86E0020F00F0084F86E00296840 +:105D6000A07C91F8082162F30100A07491F8082149 +:105D7000920862F38710A074A0896FF30B00A081D2 +:105D800091F80701A07094F85E00002120F0010056 +:105D900084F85E00204601F0C7FB286890F8F211F5 +:105DA00084F8661090F8F31184F8681090F8F411F4 +:105DB00084F86A1090F8F50184F86C003F4894F874 +:105DC0005F10001F407860F3040184F85F102046E4 +:105DD000BDE8704000F03ABF10B5384C0020241FD9 +:105DE0002080012000F02FF86070BDE81040364898 +:105DF00088E72DE9F041344E407910B3B07C00F0D3 +:105E0000030000F011FF2F4F3C6804F25E6094F82D +:105E10004F2604F6D80594F84E1600EB420000F029 +:105E2000D4FE386890F8C81890F8C90805EB40000F +:105E300000F0E2FE2549304601F01AFD0020BDE8E1 +:105E4000F0810120FBE730B51E494FF480750A68E8 +:105E500092F8071192F8F43092F8F14003F01F0322 +:105E600004F00F04A94200D929461F2B00D91F2393 +:105E70005B1C59434900641C6143C1EB4121C913B8 +:105E800092F8873AB1FA81F1C1F120019B0713D54D +:105E90000023012809D192F88B0A020703D500F0EC +:105EA0000700434201E000F00703C91801D50021B3 +:105EB00002E01F2900DD1F21C8B230BDF08601209D +:105EC000108F100004071000148D1000A95C010051 +:105ED0002DE9F05FDFF8A48583464FF00109D8F87B +:105EE00000000027ABF1020100F25E64CA460629F9 +:105EF00050D2DFE801F04F092C4F2C0310F8D46F7B +:105F0000007900F01F056DE090F8F41090F8026140 +:105F100001F01F0590F8F11001F00F0790F8E6105E +:105F2000890609D590F8501690F851060A2204EB1C +:105F3000400000F027FE8146D8F8000090F8E610F7 +:105F400049064FD590F8CA1890F8CB0844E090F86D +:105F5000FC1090F8F86001F01F0590F8F91001F0BE +:105F60000F0790F8E610890609D590F8521690F8B8 +:105F700053060A2204EB400000F004FE8146D8F8E4 +:105F8000000090F8E61049062CD590F8CC1890F84F +:105F9000CD0821E090F8F41090F8F06001F01F05B2 +:105FA00090F8F11001F00F0790F8E610890609D576 +:105FB00090F84E1690F84F060A2204EB400000F0CD +:105FC000E1FD8146D8F8000090F8E610490609D5B1 +:105FD00090F8C81890F8C9080A2204EB400000F0B5 +:105FE000D1FD82464FF48070864200D906461F2DAF +:105FF00000D91F256D1C6E4370007F1C7843C0EBD9 +:10600000402000FB09F000FB0AF0C013D8F8002084 +:10601000B0FA80F0C0F1200192F8870AC00725D0BD +:106020000020BBF10A0F13D2DFE80BF01205080BBA +:1060300016121212120592F8880A04E092F8880AE1 +:106040000CE092F8890A020700F0070000D54042F0 +:10605000091808D5002109E092F8890A0206C0F360 +:106060000210F4D4F4E71F2900DD1F21C8B2BDE8F7 +:10607000F09F70B5060003D0BDE8704000F0F4BC9E +:1060800000F018F8012814D1FD4DFE4C28780128A5 +:1060900009D0FD48A0606878E073E878A07328898B +:1060A000A0813046E8E76A792979F74800F0F9FDE0 +:1060B000F0E770BDF24B10B5D978F44C491CCAB268 +:1060C000DA70997801208A420ED8197958794143BB +:1060D000ED48FDF7CAF801F085F9A4F87600EC491F +:1060E000204601F0C5FB002010BD38B5044601F084 +:1060F00074F9E54801F076F9A4F8760000F02CFD7B +:10610000DE4D0B462A6892F8E720C2F34112009256 +:106110000246204601F04BFB00F023FD02460B46F1 +:10612000204601F070FBA07920F00200A07194F8E5 +:106130006F0020F0070084F86F0094F86E0020F0E4 +:106140000F0084F86E00286890F8E700C0F3411152 +:10615000204601F072FB286890F8E70010F0600F0D +:1061600094F85E007ED040F0010000BF84F85E002D +:10617000204600F0B7FD0521204601F05EF92868B1 +:1061800090F8F000A0702868218EB0F8F62062F335 +:106190000801218690F8F10000F00F01204601F07F +:1061A000C3F92868627D90F8EA1061F30302627512 +:1061B000B0F8EC20218A62F30B01218290F8F210F2 +:1061C000A27D61F30302A27510F8F11F0A09A17CF8 +:1061D00062F30101A17410F80B29920962F387118F +:1061E000A1740178E27961F30002E271C178617211 +:1061F00000790109204601F0A3F9A64801F0F2F860 +:10620000A4F87C00296811F8E80F820814F8270F19 +:1062100062F38300207011F8012962F300002070FE +:106220004A78520862F341002070087801096078CA +:1062300061F304106070984801F0D4F8A4F85F008E +:10624000286810F8E61FCA0814F80C1F62F34511FD +:1062500004F80B194078217860F3451104F82819E7 +:10626000204600E05CE000F0F1FC286890F8E700D0 +:10627000C0F34101204601F031F9286810F8E61F0B +:106280008A0914F8331F62F3000104F80B1902782D +:10629000520962F34101E172417B627961F30402C8 +:1062A0006271807B217960F304017C48217194F84C +:1062B0003710407860F3040184F83710784801F013 +:1062C00091F8A4F85200286834F8061FB0F8EE20C0 +:1062D00062F30B0124F8061B10F8E21F14F80A2CD5 +:1062E00061F3030204F80A2C01780A0914F8091C66 +:1062F00062F3030104F8091C01798A0814F80C1CE4 +:1063000062F3000104F80C1C0079C109207861F3E4 +:10631000000004F82B0B207840F02000207038BDDE +:1063200020F0010022E738B5044601F056F856483F +:1063300001F058F8A4F8760000F00EFC4F4D0B4623 +:106340002A6892F8C920C2F3411200920246204600 +:1063500001F02DFA00F005FC02460B46204601F044 +:1063600052FAA07920F00200A07194F86F0020F09A +:10637000070084F86F0094F86E0020F00F0084F896 +:106380006E00286890F8C900C0F34111204601F062 +:1063900054FA286890F8C90010F0600F94F85E0075 +:1063A0006BD040F0010000BF84F85E00204600F092 +:1063B00099FC286890F8D400A0702868218EB0F865 +:1063C000DA2062F30801218690F8D50000F00F0171 +:1063D000204601F0A9F82868627D90F8CC1061F39E +:1063E00003026275B0F8CE20218A62F30B0121828C +:1063F00090F8D610A27D61F30302A275B0F8D02008 +:10640000A18962F30B01A18110F8D51F0A09A17CB3 +:1064100062F30101A17410F80D29920962F387114A +:10642000A1740178E27961F30002E271C1786172CE +:1064300000790109204601F083F8164800F0D2FFE8 +:10644000A4F87C00296811F8CA0F820814F8270FF5 +:1064500062F38300207011F8012962F300002070BC +:106460004A78520862F34100207008780109607888 +:1064700061F304106070084814E086E0040710001F +:10648000D4071000108F1000208801205C8E1000AF +:1064900023600100EC6F01205C80012022A101201B +:1064A000A47C012000F09EFFA4F85F00286810F88B +:1064B000C81FCA0814F80C1F62F3451104F80B1921 +:1064C0004078217860F3451104F82819204600F03F +:1064D000BDFB286890F8C900C0F34101204600F0D8 +:1064E000FDFF296811F8C80F820914F8330F62F311 +:1064F000000004F80B090A78520962F34100E072C7 +:10650000C87B627960F304026271087C217960F3D0 +:106510000401F548217194F83710C07960F3040143 +:1065200084F83710F14800F05DFFA4F852002868A5 +:1065300034F8061FB0F8D22062F30B0124F8061BD2 +:1065400010F8E21F14F80A2C61F3030204F80A2C75 +:1065500010F81A190A0914F8091C62F3030104F867 +:10656000091C01788A0814F80C1C62F3000104F875 +:106570000C1C0078C109207861F3000004F82B0B93 +:10658000207840F02000207038BD20F001000BE79B +:1065900010B50446A422D64902F00BFED548C178B6 +:1065A000A08961F30B00A08110BD38B50446FFF748 +:1065B000EFFF00F0D1FA0022009202460B4620467F +:1065C00001F0F5F8CC4800F00DFFCC4DA4F87C00AC +:1065D000286890F8F800A070286890F8F90000F09A +:1065E0000F01204600F0A0FF286810F8F91F0A09E3 +:1065F000A17C62F30101A1740278920962F3871110 +:10660000A174817894F82D2061F3040284F82D2080 +:10661000C17894F82C2061F3040284F82C2040788F +:10662000A17D60F30301A1750021204601F005F969 +:1066300014F85E0F20F0010004F8010BAA4801795C +:10664000207861F3040004F82F092868B0F8FE10E0 +:10665000208861F30800208038BD70B5A74E03285C +:10666000346804F25E6204F6D80515D0042821D0FF +:1066700094F84F0694F84E1602EB400000F0A5FA8D +:10668000306890F8C81890F8C90800BF05EB4000C2 +:10669000BDE8704000F0B0BA94F8510694F8501676 +:1066A00002EB400000F091FA306890F8CA1890F8B8 +:1066B000CB08EBE794F8530694F8521602EB40002F +:1066C00000F083FA306890F8CC1890F8CD08DDE738 +:1066D0002DE9F8438A4D4FF00109002685F8009016 +:1066E000AE70814FDFF814820446EE700A2976D22C +:1066F000DFE801F07505091848334C62662F204623 +:10670000FFF746FF6BE02046FFF742FFB87894F8AA +:106710005F1060F3040184F85F10D8F8000090F86F +:10672000000112E02046FFF733FFD8F8001091F87F +:106730000211A170F97894F85F2061F3040284F8E3 +:106740005F20D8F8000090F8010100F00300A87065 +:1067500045E0204600F09DF841E02046FFF718FF95 +:106760000021204600F0E0FE94F85E0020F00100D9 +:1067700084F85E00787994F85F1060F3040184F87F +:106780005F1017E02046FFF710FF28E02046FFF7D4 +:106790000CFF0021204600F0C7FEB87994F85F1086 +:1067A00060F3040184F85F1094F85E0020F00100AB +:1067B00084F85E002E7012E02046FFF7B4FDF9E782 +:1067C0002046FFF7E5FE012200232046009600F058 +:1067D000EEFF204600F0C7FA204600F037FA94F8A2 +:1067E0002700C00701D06E7001E085F80190A089F4 +:1067F000C0F30B002881BDE8F8832DE9FF4100F0CC +:10680000ABF9CDE9000100F0ACF9CDE902010821B6 +:10681000684601F061FA3A4D0821287102A801F09A +:106820005BFA687130480026801E2F4F40F8026FD7 +:10683000012446600681E0B2FFF74AFB3855641C2C +:106840000A2CF8DB2A48FFF750FCAE71BDE8FF8147 +:1068500070B5274D0479A4358CB121462846FFF741 +:1068600037FFA87C00F0030000F0DEF92046FFF7B8 +:10687000F4FE2449284600F0FBFF002070BD0120F3 +:1068800070BD40F2FF10C1EB412191FBF0F0002000 +:10689000704770B50446FFF77BFE1848184A016838 +:1068A00001F5F97391F8F10100F0030592F9060082 +:1068B000854206DB1D5CA389401C65F30B03A381A5 +:1068C000907191F8F10192F9061000F003008842EE +:1068D00001DA00209071044814F85F1F407A60F3D9 +:1068E0000401217070BD000022A10120A47C0120C0 +:1068F000B88D100040071000147501200407100027 +:10690000D40710002360010010B500F079FAFFF7FA +:1069100074FFFFF761FAFFF778F9FEF749FDFEF71C +:1069200017F9FEF79CFD74490020486070217348F8 +:1069300002F0BEFC7248016891F8E700C00607D576 +:10694000BDE8104028226D4801F65A1102F031BC12 +:1069500010BD38B1012807D0022807D01720002128 +:10696000FBF7E5BC1420FAE71520F8E71620F6E758 +:106970000021016041608160C160704770B55E4C6C +:10698000604D206809E000BF55F820105E48884738 +:10699000002811D02068401C20600828F4D36068CB +:1069A0005949401C1031002260600A704860564806 +:1069B000016810308847012070BD70B50446007929 +:1069C000002550B9E07940B9A07930B9E07A20B912 +:1069D000207A10B9607900280ED04B484021103041 +:1069E00002F088FC1ECC484880E81E004248056042 +:1069F0004548FFF7C3FF012070BD10B5012000F02E +:106A000064F8072000F061F8082000F05EF8052027 +:106A100000F05BF80D2000F058F80C2000F055F85D +:106A2000012000F05DF8072000F05AF8082000F07F +:106A300057F8052000F054F80D2000F051F80C2014 +:106A400000F04EF802F0CFF800F0BFFC012000F09B +:106A500031F8072000F02EF8082000F02BF8BDE8F0 +:106A60001040052000F026B870B5234C05000ED06C +:106A7000FFF7C3FF60682449401C103160600D704F +:106A8000486021480168BDE8704010300847206820 +:106A9000401C2060BDE870401B486FE700F05CB808 +:106AA00000F05FB800F062B800F066B800F054B8CB +:106AB00000F057B800F01F0201219140400980000A +:106AC00000F1E020C0F80011704700F01F02012122 +:106AD00091404009800000F1E020C0F8801170472B +:106AE00000F01F02012191404009800000F1E020E8 +:106AF000C0F8801270470000E00710005C800120A1 +:106B00000407100030980100008F100070B50023BA +:106B1000144609E031F9135031F9146035446D1011 +:106B200020F813505B1C641C9342F3DB70BD30B43F +:106B300000244BB90CE000BF30F8143031F8145089 +:106B40002B4420F81430641C9442F5DB30BC7047B1 +:106B500030BC520002F02DBBA2480068C16A806AB6 +:106B60007047A0480068416A006A70479D48006805 +:106B700000F67C2003C870479A48006800F674202D +:106B800003C87047F0B500242546974E4FF40067C0 +:106B900014E000BF30F81530C3F30B035FEAD32CC9 +:106BA00000D03343002B00DA5B429C4200DA9CB2F7 +:106BB000BC4202D340F2FF7402E06D1C8D42E9DB5F +:106BC000D4400120A04080B2F0BD30B5884B874C46 +:106BD0005A68824202D1DA688A420AD0002206E06C +:106BE00030F81250C5F30B0524F81250521C8A429B +:106BF000F6DBD960586030BD30B57D4B7D4C9A686E +:106C0000824202D11A698A420DD0002207E000BFF9 +:106C100030F81250C5F30B0524F81250521C8A426A +:106C2000F6DB1961986030BD70B5044672480168A2 +:106C300002290AD16E4D29788C4206D000EB8400DF +:106C4000D0F89C0000F0E1FB2C7070BD10B504463C +:106C500090F82800800604D5684800F0C3FBA4F82B +:106C60008C0010BD10B5044690F8280080060AD5A7 +:106C70006248283000F0B6FB24F88E0F5F48483099 +:106C800000F0B0FB608010BD10B5044690F82800FD +:106C9000800605D55948703000F0A4FBA4F88E009A +:106CA00010BD70477047704702004FF0000000D1E0 +:106CB0000846704702460020012A00D10846704766 +:106CC00010B5044690F8280080060AD54B4890304D +:106CD00000F088FB24F88E0F4848B03000F082FBAB +:106CE000608010BD3F490A6892F8B020930910F8FF +:106CF0003E2B63F3820200F83E2C0B6893F8B03011 +:106D00005B0963F3451200F83E2C0968B1F8B7201F +:106D1000028291F8B620837F62F30713837791F89C +:106D2000B3201309027D63F30612027531F8B13FF7 +:106D3000028B63F30902028311F8012C9308827D10 +:106D400063F3861282758A78C37D62F30303C37589 +:106D5000B1F80330B0F81B2063F30802A0F81B2041 +:106D600009894182704710F8371F41F0100100F87F +:106D70001F1930F80C2CC17E6FF30B02103220F873 +:106D80000C2C30F8082C21F023016FF30B02403259 +:106D900020F8082C082200F8162C90F8472041F023 +:106DA0000C0122F01F0280F84720028B6FF30802CB +:106DB0000283C176C18A6FF30B013F31C182417DED +:106DC00021F01F014175017D21F01F01017590F82F +:106DD000461021F0010180F84610017C41F02001AD +:106DE000017470470407100000F0FFFFA47C01202D +:106DF000E8071000A47E0120508F1000847F01203E +:106E0000704710B500F095FD08B1012010BD08488D +:106E100000F078FD002010BD064810B5006890F81D +:106E20007000400701D500F079FD012010BD000081 +:106E3000196A0100040710003D48016821F00401AF +:106E4000016000F009BF10B5FFF7F6FF10BD10B5E7 +:106E5000FFF7F2FF10BD10B5FFF7EEFF10BD10B544 +:106E6000FFF7EAFF01F08DFC10BD10B5FFF7E4FF5E +:106E700000F0D8FA10BD10B5FFF7DEFF01F097FD66 +:106E800010BD10B5FFF7D8FF01F0FCFD10BD10B527 +:106E9000FFF7D2FF01F061FE10BD10B5FFF7CCFF88 +:106EA00001F0C8FE10BD10B5FFF7C6FF01F041FFAD +:106EB00010BD10B5FFF7C0FF01F0A8FF10BD10B561 +:106EC000FFF7BAFF02F00FF810BD10B5FFF7B4FFDF +:106ED00002F0E8FA10BD10B5FFF7AEFF02F0BEFAFF +:106EE00010BD10B5FFF7A8FF10BD10B5FFF7A4FF48 +:106EF00010BD10B5FFF7A0FF10BD10B5FFF79CFF48 +:106F000002F038F810BD10B5FFF796FF10BD10B5B0 +:106F1000FFF792FF10BD10B5FFF78EFF10BD10B543 +:106F2000FFF78AFF10BD10B5FFF786FF10BD704751 +:106F300010ED00E00EB5002000900190029009488D +:106F400000F033FE684600F034FEFBF7DDFFFBF790 +:106F500015FE00F031F800214720FBF7E8F9012089 +:106F60000EBD0000600060221A4910B501200870B3 +:106F70001949002008601949086019490860194931 +:106F8000086000F07FF900F019F900F07DF80020AA +:106F900010BD10B5124802F07FF8104908600E4984 +:106FA0000968884207D00B480078022803D1BDE861 +:106FB0001040E9F7DBB910BD10B5FFF7EAFF05494E +:106FC00002200870E9F7B6F94FF0FF3010BD01203C +:106FD0007047000044081000480810004C081000DA +:106FE000500810005408100070B50D460446C169E1 +:106FF0008068CC2202F054F9E169A06800220844BC +:107000004FF0807140F8041C216A40E9032140F8E8 +:10701000102C40F8142C40F8182C40F81C2C4FF081 +:107020000B3140E909154FF00A3140F8281C4FF0A8 +:10703000093140F82C1C4FF0083140F8301C4FF05B +:10704000073140F8341C4FF0063140F8381C4FF03F +:10705000053140F83C1C4FF0043140F8401D70BD34 +:1070600081694FF0CC330A689A4208D14A689A4243 +:1070700005D18A689A4202D1C968994202D0406813 +:10708000FBF7C3BD7047000010B5A021494802F0CE +:1070900031F9002010BD70B50646464800EB0614D5 +:1070A000E9F79CF90546207828B12846E9F79EF9CA +:1070B0006FF0010070BD0320207000206660E0606A +:1070C00004F1080001F0C2FF2846E9F78FF900201B +:1070D00070BD2DE9F0410F463649002501EB001443 +:1070E0002E46E9F77BF98046E0683843E06004F11A +:1070F0000800074601F0D0FF0CE0E168C26A1142C7 +:1071000003D000F00FF9012600E06D1C2946384637 +:1071100001F0B8FF0028F0D10EB1FFF73AFF40466A +:10712000E9F764F90020BDE8F08170B50D4621490A +:1071300001EB0014E9F752F9E168A943E160E9F7CE +:1071400055F9002070BD70B50C461A4901EB0015C9 +:1071500000202060E9F742F9E9682160E9F746F983 +:10716000002070BD2DE9F0410D4612491E469046A3 +:1071700001EB0014E9F732F907460F480068C562D1 +:10718000E168294203D104F1080100F0DDF8384636 +:10719000E9F72CF9E9F722F9E16829403160B8F103 +:1071A000010F02D1E168A943E160E9F71FF900206E +:1071B000B9E70000FC8F10004808100010B5C82186 +:1071C0002E4802F097F8002010BD2DE9F041064648 +:1071D0002A4900EB8600174601EB8004E9F7FEF828 +:1071E0000546207830B12846E9F700F96FF0010034 +:1071F000BDE8F0810220207000206660C4E90270C2 +:1072000004F1100001F022FF2846E9F7EFF8002012 +:10721000EEE770B5194900EB800001EB8004E9F757 +:10722000DDF80546D4E90201814205DB144804F18A +:107230001001006800F088F8E068401CE060284613 +:10724000E9F7D4F8002070BD70B50C4900EB800060 +:1072500001EB8004E9F7C2F80546E06808B1401E7A +:10726000E06004F1100001F017FF10B1206900F098 +:1072700011F82846E9F7BAF8002070BD9C9010007C +:107280004808100010B54FF4F0713C4802F032F895 +:10729000002010BD10B5044690F8240002280BD041 +:1072A000204601F0FBFE022084F8240034492046E9 +:1072B00001F0D0FEFFF76DFE002010BD2DE9F05F5C +:1072C00006460AA806EB460190E8000E2B481D462C +:1072D00000EB01149046207818B16FF00100BDE872 +:1072E000F09FE9F77BF8074601202070C4F814806E +:1072F000C4E9016504F11801002081E8200684F842 +:107300002400E0602061C4E90A8059462046FFF766 +:107310006BFEA0602046FFF7BDFF3846E9F766F830 +:107320000020DCE710B5044690F82400022809D0BC +:10733000204601F0B3FE022084F8240010492046C4 +:1073400001F088FE002010BD70B5044690F82400BE +:107350000D4602280BD1204601F0A0FE032084F840 +:1073600024002946204601F075FEFFF712FE00209A +:1073700070BD0448006840687047000064911000C8 +:107380005008100048081000724810B50021016034 +:10739000012202600160704C6920A0710420E9F7AD +:1073A0002FF80820A07110BD10B5FFF7EDFF6B4856 +:1073B00000210170416000F0F6F9BDE8104000F0D6 +:1073C000E2BA01F0FCBC01F067BD10B501F064FD4C +:1073D00001F0F5FCBDE81040E6E7A422604901F0A9 +:1073E000E8BE704710B50446800702D00220FFF7C0 +:1073F000B0FA4FF480302044C0F34F0010BD014676 +:1074000055489822A43001F0D4BE534AA43200213A +:1074100042F82100491C2629FADB704701F019BD0A +:1074200001F097BC4D4810B5406810B1BDE8104060 +:1074300000470020FFF78DFA10BD062937D2DFE89C +:1074400001F0112437243603017821F0120100F8ED +:107450004D1B017821F0030100F8071B017821F092 +:1074600080010CE0017821F0020141F0100100F8E8 +:107470004D1B017821F0030100F8071B12E000F812 +:10748000441B017821F0010110E00278012942F04B +:107490001202027000D0032110F84D2F61F3010297 +:1074A00000F8072B017841F08001E8E70170704790 +:1074B000017821F0020141F0100100F84D1B017824 +:1074C00021F00301891C00F8071B017841F08001BD +:1074D00000F8441B017841F00101E7E790F829200A +:1074E000022904D0032922F0400102D104E042F035 +:1074F000400121F0800101E041F0800180F8291075 +:10750000704790F82920012904D0022907D022F0E1 +:10751000100101E042F0100121F0200101E042F0F1 +:10752000300180F829107047C278002961F3030206 +:10753000C27004D010F85E1F41F004010170704762 +:10754000C27A012961F30302C27202D942F010012A +:10755000C17270479004002200000320FC07100055 +:107560005098010001EB810102EBC101405C010672 +:1075700002D500F07F0040427047002B04DA5B42E6 +:10758000DBB243F0800301E003F07F0301EB8101F4 +:1075900002EBC101435470472DE9F05F0025DDE99E +:1075A0000A7891469A4683462E462A4601200021B3 +:1075B00001F0C8FD00EA090001EA0A01084314D0FD +:1075C000002422460120002101F0BCFD384001EAE0 +:1075D0000801084305D00023224631465846FFF7EC +:1075E000CCFF641C282CECDB761C6D1C382DDCDBFE +:1075F000BDE8F09F405C010602D500F07F004042EC +:107600007047002A04DA5242D2B242F0800201E00E +:1076100002F07F0242547047F0B5002415460E4632 +:107620008446234601270FE006EBE30003F0070141 +:10763000007807FA01F2024205D00022194660469E +:10764000FFF7DFFF641C5B1CAC42EDDBF0BD405C70 +:10765000704742547047F0B50024234601260DE0E0 +:1076600001EBE30503F007072D7806FA07FC1CEA97 +:10767000050F02D00025C554641C5B1C9442EFDB4F +:10768000F0BD405C704742547047405C70474254C4 +:10769000704700002DE9F047334C54F83C8F676881 +:1076A000E668257CDFF8C4900121C9F800104FF48A +:1076B0002070E8F7A5FE0021C9F80010C4F800808A +:1076C0006760E6602574BDE8F08727480021C16344 +:1076D0000164816480F84C10704770B500240D4639 +:1076E00002460120214601F02DFD35B31E4A4832E5 +:1076F00010601171FFF7CEFF002000F023F800B1F9 +:107700000124FFF7C7FF012000F01CF808B144F086 +:107710000204FFF7BFFF022000F014F808B144F0A4 +:107720000404FFF7B7FF032000F00CF808B144F0A1 +:107730000804FFF7AFFF204670BD0B4A3C32C2E998 +:107740000001D7E740F02001074810B580F8A310EA +:10775000E52181714FF42070E8F752FE0448D0F81B +:10776000C002C0B210BD00000000032068146022F7 +:107770000010602253480168002901D00120084709 +:10778000704710B5FFF71FFE4F49022008704F49A0 +:10779000002008604B480168002903D0BDE8104074 +:1077A0000020084710BD47490020086070477FB59A +:1077B00004460399089DC1F314010391082102A80E +:1077C00000F08AFA012D02D0022D04D006E0C01C80 +:1077D00020F0010002E0C01D20F00300DDE90212EC +:1077E00044F83C1F6260217A60F3060121727FBD7C +:1077F000012340F83C3F002343605143027A61F388 +:107800000602027270471FB50446039902A801F0F0 +:107810003F010391082100F05FFADDE90212A16443 +:1078200084F84C2014F8701F60F3050104F81E1949 +:10783000E17F60F30501E1771FBD08B524A212685E +:1078400000921DF8012010F85D1F62F30101017024 +:1078500008BD1D49032008701C491E4808601E49C8 +:107860000120C1F8C0001D494FF4FA70FFF7D6BDE2 +:1078700010B50B46817921F00D0141F0E0018171D5 +:10788000817C8A091BD08A0962F3871181740D49B2 +:107890000D4A0B60032111700C4A0E49116001461C +:1078A000A4220F4801F085FC0B490120C1F8C0005B +:1078B000BDE8104009494FF4FA70FFF7AFBD01224F +:1078C000E2E7000004081000FC07100000081000A8 +:1078D00000010200337701000000602225770100DB +:1078E0000000032016480178012908D10221017007 +:1078F0001448016819B100220260104608470120AF +:10790000FFF727B80E4A012111700E4908600E4991 +:10791000E82088710D490C20FFF782BD0A49082034 +:1079200088710B4900200862054908700549086004 +:10793000704703480078002800D0012070470000FD +:10794000FC071000080810000000032095780100D3 +:107950000000602268480168002901D00120084722 +:10796000704710B5FFF72FFD644902200870644985 +:107970000020086060480168002903D0BDE810407D +:107980000020084710BD5C490020086070477FB5A3 +:1079900004460399089DC1F314010391082102A82C +:1079A00000F09AF9DDE90212E163226494F84420C0 +:1079B000C1B261F3060284F844200A2D0FD00B2DCA +:1079C0000DD014F8720F61F305002070607861F338 +:1079D00005006070A07820F00800A0707FBD14F84A +:1079E000721F401C60F305012170617860F305018E +:1079F0006170A07840F00800EFE71FB504460399D6 +:107A000002A801F03F010391082100F065F9DDE9CA +:107A10000212A16484F84C2014F8701F60F3050171 +:107A200004F81E19E17F60F30501E1771FBD30B551 +:107A300034A28CB03CCA8DE83C0036A20DF1100C8B +:107A40003CCA8CE83C0037A20DF1200C3CCA8CE803 +:107A50003C0004AA535C427E63F3050242761DF8A3 +:107A60000130027E63F34202027608AA525C8179F9 +:107A700062F3830181710CB030BD2049042008708D +:107A80001F492C4808602C490120C1F8C0002B492F +:107A90004FF4FA70FFF7C2BC10B50B46B0F85610A1 +:107AA00041F00101A0F85610817C8A0921D08A0991 +:107AB00062F3871181748179104A21F0010141F04C +:107AC000E00181710C490B60042111700C4A1949C5 +:107AD00011600146A4221A4801F06BFB16490120EF +:107AE000C1F8C000BDE8104014494FF4FA70FFF728 +:107AF00095BC0122DCE700000C081000FC07100018 +:107B00000008100000000202010103030303000249 +:107B1000000000000202020202020202010102024F +:107B20000101000002030203020302030203020236 +:107B300002030000137901000000602205790100B2 +:107B4000000003204E49012008601722410701F878 +:107B5000272F0B2281F841204949183908604FF03E +:107B60000851C1F8C403464B0022B0331A60454A9D +:107B70001060121D1060424A943A1060C1F8680308 +:107B8000C1F8740370473E4901209439086070477A +:107B90003B4900209439086070474FF0005000883E +:107BA00070474FF00050807870474FF000514860A8 +:107BB0007047354902680A6042684A608068886098 +:107BC000704731490A6802604A684260896881608A +:107BD00070472B4901203039086070474FF0005042 +:107BE00010F8221F21F00301017070474FF000537D +:107BF00003F81F0F5970987862F30300987070476C +:107C000022480068704721490860704710B54FF05E +:107C10000054E27E202322F0AF0203EA4013134314 +:107C2000042202EA8000034301F003000343E376E9 +:107C300010BD4FF0005090F8220010F0030005D066 +:107C4000012805D0022805D0114870471148704717 +:107C5000114870471148704770477047104901201C +:107C6000C1F8DC0070470E490020C1F8DC00704705 +:107C70000348F030006808B10120704702207047C7 +:107C8000CC040022801E00220800002010081000F2 +:107C900000127A000090D0030048E8010024F400AC +:107CA00000006022F0B50746002003462F4E10E08A +:107CB00057F8235003224FEAC20C45FA0CF484EA29 +:107CC0002064E4B2521E56F8244084EA0020F2D523 +:107CD0005B1C8B42ECDBF0BD30B50446234B00202F +:107CE000103B08E0625C02F00F0503EB12125D5DD1 +:107CF000127828441044491EF4D230BD10B584686F +:107D00000368E443A3420AD1C4684368E443A3423E +:107D100005D15B1C0B6000681060012010BD0020C5 +:107D200010BD3CB50446002501AA6946FFF7E6FFF1 +:107D3000012809D1009904F11000091FFFF7B2FFD3 +:107D40000199884200D1012528463CBD30B50D4639 +:107D50000446091F1030FFF7A5FF6D1E6560E9435B +:107D6000E1602060C043A06030BD000004990100C4 +:107D700001468000B1F5803F02D21038C0F31000F8 +:107D80007047C0F387207047B0F5802F02D21030C3 +:107D9000C0F31000C0F38F00704730B5FE4C0125D2 +:107DA0002560E50603F01F0385F86B30002304E02F +:107DB00051F8235040F823505B1C9342F8DB00201D +:107DC000206030BDF0B5F44F01233B605C0784F8C0 +:107DD0006B309B1E0360002312E051F8234040F8F3 +:107DE0002340002450F8235051F82360B54206D0B8 +:107DF0006D1C04D1641C40F82360032CF2D35B1C7F +:107E00009342EADB00203860F0BDF0B513460A4625 +:107E10000546002498184FF48326602801D90124D0 +:107E200011E0002107E05F1856F82700401C01D040 +:107E300011460224491C9142F5D324B906EB830074 +:107E40002946FFF7BFFF2046F0BD10B503460846A0 +:107E5000FFF78EFF0146BDE810409200184601F082 +:107E6000EDB92DE9F0414FF000580C46D8F81470E8 +:107E70000125C0F38F066FF48041C8F814100E205E +:107E800000F013FA204600F01BFA0200C3484FF03E +:107E9000010118D00160A4F58034404620F8726FCB +:107EA0004480602200F8012CBD4A1160BB4AC432F4 +:107EB000116030BF81797238890700D00025476191 +:107EC0002846BDE8F08100220260E6E72DE9F05F78 +:107ED0001546DFF8C4B2002601270A4604464FF0D3 +:107EE000005CB1F5882F15D3A30AFFF741FF59466F +:107EF000CBF8007003F01F038CF86B30002304E014 +:107F000052F8234040F823405B1CAB42F8DB0E6084 +:107F1000BDE8F09FDCF81490C1F38F08E2466FF4DF +:107F20008041CCF814100E2000F0BFF9CBF800709F +:107F3000204600F0C5F90100984819D00760A4F563 +:107F40008034AAF87280AAF874406D1EAAF87650A0 +:107F500040218AF8711092490E609049C4310F6037 +:107F60000AF1520030BFCBF8006040F83E9CCFE7EA +:107F70000660E6E72DE9F0414FF000540F4654F853 +:107F8000146F85086FF4804020600E2000F08DF99A +:107F90000020A066A4F85E507F1EA4F8627084F8EA +:107FA0005D007F4908607D490120C431086030BF11 +:107FB000E06E266085E770B506460C4601F11000BC +:107FC000111F154689B2FFF7D5FF2060681E60605B +:107FD00020682A46C043A06060682146C043E06034 +:107FE0003046BDE8704071E7F0B507460020044612 +:107FF0006C4E15E057F8245003234FEAC30C45FAA2 +:108000000CF280EA02600822002802DA86EA4000C8 +:1080100000E04000521E002AF6DC5B1EEDD5641C19 +:108020008C42E7DBF0BD30B550F8084B50F8085BE8 +:1080300030F80C1C491C89B2FFF7D6FF844204D1EA +:10804000E043854201D1012030BD002030BD2DE943 +:10805000F0410126750704466F696FF4804068613E +:108060000E2000F022F94FF00008C5F87C80204671 +:1080700000F026F9020049494FF0010015D00860D0 +:10808000A4F58034A5F87440202185F87110444986 +:1080900008604249C431086030BF95F87800800715 +:1080A00000D000266F6130460BE7C1F80080E9E799 +:1080B00000B50B46FFF75CFE82680168D24391422F +:1080C00008D14268C068C043824203D1521C1A8062 +:1080D000012000BD002000BDF8B5044610300D465B +:1080E0000646FFF7BEFE012801D00020F8BD694614 +:1080F0002846FFF7DDFFBDF80000001F81B23046C3 +:10810000FFF738FF2060BDF80010C043491E6160D2 +:10811000A060C843E0600120F8BDF0B5B1B00746EB +:108120006D46214E0124C021284601F0E3F80020CD +:1081300056F8201045F82010401C3028F8D31B4971 +:108140000098884210D1029881B205A80446FFF732 +:108150004BFF0199814206D1AC222146384601F0FD +:108160006DF8002400E0032431B02046F0BD70B566 +:1081700094B004466D460E4E5021284601F0BAF8E0 +:10818000002056F8201045F82010401C1428F8D381 +:1081900008486FF002050FE0C41B0022780D002292 +:1081A0001C0F00221B000080481D0400B2570E70F7 +:1081B000AC1E04005C000D60009981422ED1A81015 +:1081C00020606060A060E0602061029881B205A834 +:1081D000FFF70AFF0199814220D1BDF8381045F21E +:1081E000AA5081420CD19DF81D1021609DF81C10F1 +:1081F00001F00F0161609DF81E1001F00F01A160F8 +:10820000BDF83C10814201D10899E160BDF84010F1 +:10821000814201D10998206114B070BD256065606C +:10822000A560E5602561F7E770B586B004466D4648 +:10823000274E1421284601F05DF8002156F8210050 +:1082400045F82100491C0529F8D3009820600198C1 +:1082500060600298C0B2A0600398C0B2E060049869 +:10826000C0B2206106B070BD1CB50020184A009055 +:10827000843A6B460146019052F8214043F8214070 +:10828000491C0229F8D3BDF80010A1F5AA42AA3A68 +:108290000AD1BDF80420114206D19DF802109DF8C4 +:1082A0000620114200D108461CBD00F01F0201212A +:1082B00091404009800000F1E020C0F88012704732 +:1082C000B0F5803F01D200207047012070470000C8 +:1082D000601F04004FF00050002180F83D1080F82E +:1082E0003E1080F83F103F2280F8322000F8301F07 +:1082F000027141714270017241728172C172C17129 +:1083000070474FF00052062817D2DFE800F003064E +:10831000090F171A12F83D0F04E012F83D0F07E09D +:1083200012F83E0F20F00F00084305E012F83E0F50 +:1083300020F0F00040EA01101070704712F83F0F73 +:10834000F0E712F83F0FF3E730B50D460121814009 +:10835000CCB20021FFF7D5FF29784FF0005000295B +:1083600090F8321001D0214300E0A14380F8321090 +:108370006978002990F8301001D0214300E0A14332 +:1083800080F83010A978002990F8341001D02143EA +:1083900000E0A14380F83410E978002990F8351006 +:1083A00001D0214300E0A14380F83510297900294C +:1083B00090F8311001D0214300E0A14380F8311042 +:1083C000002180F8381080F8391080F83A1080F8D1 +:1083D0003B1080F8371030BD774A1160764A002193 +:1083E00034321160121D08B1116070470120106015 +:1083F000704730B501248440E0B24FF000540029AA +:10840000039D94F8321001D0014300E0814384F8C9 +:10841000321094F830100AB1014300E0814384F82F +:10842000301094F834100BB1014300E0814384F81C +:10843000341014F8351F0DB1014300E08143217061 +:1084400030BD01238340D8B24FF00053002993F888 +:10845000381001D0014300E0814383F8381013F84D +:10846000391F0AB1014300E08143197070470123AD +:108470008340D8B24FF00053002993F83A1001D04E +:10848000014300E0814383F83A1013F83A1F0AB120 +:10849000014300E08143197070472DE9F04705461C +:1084A0000120A840C4B21F46914688460A20DDF844 +:1084B00020A000F06BF80B2000F068F80A2000F014 +:1084C00070F80B2000F06DF84FF0005696F8380069 +:1084D000A04386F8380096F83A00A04386F83A00A0 +:1084E00096F82E00A04386F82E00344A0020B8F1FA +:1084F000000F42F825000BD096F83810214386F87B +:10850000381096F83A10214386F83A1042F8257050 +:1085100096F83910A14386F8391096F83B10A1431C +:1085200086F83B1096F82F10A14386F82F102349A8 +:108530002031B9F1000F41F825000BD096F8390031 +:10854000204386F8390096F83B00204386F83B002C +:1085500041F825A096F8380010B10A2000F00BF879 +:1085600096F83900002804D0BDE8F0470B2000F051 +:1085700002B8BDE8F08700F01F02012191404009D8 +:10858000800000F1E020C0F80011704700F01F02E9 +:10859000012191404009800000F1E020C0F88011E5 +:1085A000704700F01F02012191404009800000F156 +:1085B000E020C0F8801270470405002244931000A8 +:1085C0002DE9F047417ACA074FF0000101D0554A22 +:1085D000516001277D0785F8E57085F8E470C5F8DE +:1085E000C010C5F8E81085F8E11085F8E310DFF851 +:1085F00038A1067A04680AF10709072E00D9072670 +:1086000000216DE04A1CD3B201EB810214F8028014 +:108610000AF80180D0F804C022443CF8118029F8FF +:10862000118092F803C0BCF1010F02D0BCF1030F1E +:1086300007D195F8E5C007FA03F84CEA080C85F86D +:10864000E5C090F809C05FEACC7C0FD192F803C076 +:10865000BCF1020F02D0BCF1030F07D195F8E4C0C2 +:1086600007FA03F84CEA080C85F8E4C001EB410C6A +:1086700021F00108E04492F801C00CF0070C0CFA5C +:1086800008FCD5F8C0804CEA080CC5F8C0C092F8C8 +:1086900002C04FEA81080CF00F0C0CFA08FCD5F868 +:1086A000E8804CEA080CC5F8E8C090F809C05FEA19 +:1086B000CC7C14D11279D20707D095F8E12007FAC3 +:1086C00003FC42EA0C0285F8E1202279D20606D5A5 +:1086D00095F8E32007FA03F31A4385F8E320491CD1 +:1086E000B1428FD3D5F8E8006864BDE8F0870E4A40 +:1086F000D21D22F81010704710B504460B480068D0 +:1087000038B1A068FFF75CFF2068BDE8104000F0BA +:108710000FB8E068FFF754FF6068BDE8104000F054 +:10872000D3BC000000200022AB000020BC050022CA +:1087300010B54F4B016800249960818859800289E7 +:108740009A801C704FF00053A3F81A21A3F81E1151 +:10875000C088A3F8200147480122C0F8D821C0F8FA +:10876000DC21C0F8C421C0F8CC21C0F8D421C0F865 +:10877000802172B6D0F808120029FBD1426062B69F +:1087800010BD2DE9F0413B4DD5F85C01384F2E046A +:108790000124BA6850B3B6F81C815FEA08000FD014 +:1087A000D5F8540110B9D5F8000148B1414601206F +:1087B0009047C5F8D842D5F8540108B1C5F8D4425D +:1087C000BA684146022090470178022902D0032965 +:1087D00002D008E0418800E07988A6F81E11808860 +:1087E000A6F81A013C70C5F8DC4238E0D5F844011F +:1087F00080B1B6F81C1103209047387838B17888DA +:10880000A6F81E01B888A6F81A0100203870C5F82D +:10881000C44224E0D5F8580130B1B6F81C1101204B +:108820009047C5F8D8421AE0D5F84C0128B9D5F8D8 +:10883000540110B9D5F8000188B1B6F81C1119B16E +:1088400001209047C5F8D842D5F84C0110B1C5F8C1 +:10885000CC4204E0D5F8540108B1C5F8D442D5F8AB +:108860000001002801D0C5F88042BDE8F081000079 +:108870001408100000200022F64900200860091D9D +:108880000860091D0860091D0860091D0860091DB0 +:108890000860091D0860091D0860EF4901220A608F +:1088A000ED4914310860510701F8500FFF234B7058 +:1088B00001F8050C10234B808A80E8490860486065 +:1088C0008860C860086148618861C8610862704753 +:1088D0007047E24A1160DF4900220A6000EB800025 +:1088E0004FF6FF7202EA40004FF00052A2F8580023 +:1088F000012008607047D94B10B5D64A1960002195 +:1089000011604FF0005191F85140E40707D01B6A05 +:1089100058438009A1F858000120106010BD00EBF9 +:10892000C00303EB00104FF6FF7303EA8000F1E78A +:108930004FF00050B0F8580070474FF0005090F8DA +:108940002200C0F3810028B1012805D0022805D0FB +:10895000C3487047C3487047C3487047C34870470F +:1089600070B54FF0005494F85100BA49C2074FF067 +:10897000000001D0086070BD656972B6626942F09E +:10898000040262610860B4F8581009B1A4F85800F4 +:10899000FFF74FF90146FFF7D0FFB1FBF0F0E7F723 +:1089A0002FFD6561022000F03BFB62B670BDAB4855 +:1089B00010B5002104680160FFF7D2FF1CB1A44686 +:1089C000BDE8104060470020FFF782FF10BDA34ABA +:1089D0005160A0490022091D0A6000EB80004FF69B +:1089E000FF7202EA4000CA06A2F85A00012008609D +:1089F00070479A4B10B55960964A0021121D1160BC +:108A0000D10691F85140A40708D400EBC00303EB52 +:108A100000104FF6FF7303EA800002E01B6A584320 +:108A20008009A1F85A000120106010BD4FF00050DD +:108A3000B0F85A00704770B54FF0005494F85100E8 +:108A40008B4982074FF000001AD4656972B66269DB +:108A500042F0080262610860B4F85A1009B1A4F843 +:108A60005A00FFF7E6F80146FFF767FFB1FBF0F0A9 +:108A7000E7F7C6FC6561032000F0D2FA62B670BD6C +:108A8000086070BD754810B5002144684160FFF76B +:108A9000D2FF1CB1A446BDE8104060470120FFF79B +:108AA00017FF10BD6D4A916071490022091D0A60CF +:108AB00000EB80004FF6FF7202EA40008A06A2F83F +:108AC0005C00012008607047644B10B59960684AEB +:108AD0000021121D1160910691F85140640708D4DD +:108AE00000EBC00303EB00104FF6FF7303EA8000B6 +:108AF00002E01B6A58438009A1F85C000120106065 +:108B000010BD4FF00050B0F85C00704770B54FF0EA +:108B1000005494F85100574942074FF000001AD40E +:108B2000656972B6626942F0100262610860B4F869 +:108B30005C1009B1A4F85C00FFF77BF80146FFF771 +:108B4000FCFEB1FBF0F0E7F75BFC6561042000F090 +:108B500067FA62B670BD086070BD404810B500216C +:108B600084688160FFF7D2FF1CB1A446BDE81040C5 +:108B700060470220FFF7ACFE10BD384AD1603D4986 +:108B80000022091D0A6000EB80004FF6FF7202EA26 +:108B900040004FF00052A2F85E00012008607047CC +:108BA0002E4B10B5D960334A0021121D11604FF0D1 +:108BB000005191F85140240708D400EBC00303EBA7 +:108BC00000104FF6FF7303EA800002E01B6A58436F +:108BD0008009A1F85E000120106010BD4FF0005028 +:108BE000B0F85E00704770B54FF0005494F8510033 +:108BF000214902074FF000001AD4656972B6626914 +:108C000042F0200262610860B4F85E1009B1A4F875 +:108C10005E00FFF70EF80146FFF78FFEB1FBF0F0A4 +:108C2000E7F7EEFB6561052000F0FAF962B670BD6A +:108C3000086070BD094810B50021C468C160FFF725 +:108C4000D2FF1CB1A446BDE8104060470320FFF7E7 +:108C50003FFE10BD40090022C00400222008100081 +:108C600000093D000048E8010024F40000127A00E9 +:108C700044090022480900224C090022EE4A1161F1 +:108C8000EE4900220A6000EB80004FF6FF7202EA14 +:108C900040004FF00052A2F86000012008607047C9 +:108CA000E54B10B5E54A1961002111604FF0005104 +:108CB00091F85140E40608D400EBC00303EB001028 +:108CC0004FF6FF7303EA800002E01B6A58438009F5 +:108CD000A1F860000120106010BD4FF00050B0F806 +:108CE0006000704770B54FF0005494F85100D349BC +:108CF000C2064FF000001AD4656972B6626942F08C +:108D0000400262610860B4F8601009B1A4F8600024 +:108D1000FEF78FFF0146FFF710FEB1FBF0F0E7F71B +:108D20006FFB6561062000F07BF962B670BD0860DC +:108D300070BDC14810B5002104690161FFF7D2FF81 +:108D40001CB1A446BDE8104060470420FFF7C0FDF9 +:108D500010BDB94A5161B9490022091D0A6000EBF2 +:108D600080004FF6FF7202EA40004FF00052A2F876 +:108D70006200012008607047AF4B10B55961AF4ADF +:108D80000021121D11604FF0005191F85140A406CE +:108D900008D400EBC00303EB00104FF6FF7303EAA7 +:108DA000800002E01B6A58438009A1F8620001209C +:108DB000106010BD4FF00050B0F86200704770B501 +:108DC0004FF0005494F851009D4982064FF0000086 +:108DD0001AD4656972B6626942F080026261086005 +:108DE000B4F8621009B1A4F86200FEF722FF014650 +:108DF000FFF7A3FDB1FBF0F0E7F702FB6561072089 +:108E000000F00EF962B670BD086070BD8A4810B5FA +:108E1000002144694161FFF7D2FF1CB1A446BDE8BF +:108E2000104060470520FFF753FD10BD824A916155 +:108E300083490022091D0A6000EB80004FF6FF7293 +:108E400002EA40004FF00052A2F8640001200860DE +:108E50007047794B10B59961794A0021121D116054 +:108E60004FF0005191F85140640608D400EBC00364 +:108E700003EB00104FF6FF7303EA800002E01B6A69 +:108E800058438009A1F864000120106010BD4FF024 +:108E90000050B0F86400704770B54FF0005494F87B +:108EA0005100684942064FF000001AD4656972B655 +:108EB000626942F4807262610860B4F8641009B1BA +:108EC000A4F86400FEF7B5FE0146FFF736FDB1FBDE +:108ED000F0F0E7F795FA6561082000F0A1F862B6B6 +:108EE00070BD086070BD544810B50021846981616F +:108EF000FFF7D2FF1CB1A446BDE810406047062032 +:108F0000FFF7E6FC10BD10B5FEF77AFE4FF00051FA +:108F100091F8222042F21073B0FBF3F0C2F3810209 +:108F2000521CD040B1F85420C96C51438909B0FBA0 +:108F3000F1F010BD43490022091D0A603E4A126A41 +:108F400050434FF000528009A2F8660001200860EB +:108F500070473C490020091D086070473649C861C8 +:108F600039490120C1F8DC003649A0310860091DEB +:108F700008607047304A10B50020D169D061324A8C +:108F8000C2F8DC0051B12F4AA03210604FF00050FF +:108F9000C06CBDE8104020F07F400847FF20FFF77D +:108FA00097FC10BD10B50446FEF72AFE4FF00051A5 +:108FB00091F8221042F21072B0FBF2F0C1F381017D +:108FC000491CC8400003B0FBF4F01B49086210BD07 +:108FD00030B54FF000550124844095F8510009B197 +:108FE000204300E0A04385F8510095F84B000AB1FA +:108FF000204300E0A04385F84B0015F8500F0BB15B +:10900000204300E0A043287030BD4FF0005010F81E +:109010004A1FC079814301D001207047002070476A +:1090200000F01F02012191404009800000F1E02082 +:10903000C0F880127047000020081000500900227C +:10904000540900225809002200006022002101601A +:109050000846704730B50A6812B10B46846A08E0CA +:1090600000220860C0E903210AE002F10C03D26883 +:1090700012B1956AA542F8DC1A68C0E903211860AC +:10908000002030BD0068002201E0C068521C8A4206 +:1090900001D00028F9D170470068704702690AB111 +:1090A000116831B96FF00400704701F10C02C96812 +:1090B00039B18142F9D1C9681160002101610846C6 +:1090C00070476FF003007047017C31B14FF00051E1 +:1090D00011F82D2F42F002020A70194902680A6045 +:1090E00042684A6082688A60C068C860704730B46D +:1090F0004FF0005111F8E00F0A8AC968104BC407FD +:1091000008D09B68002B0BD0A2F57F44FF3C07D012 +:1091100030BC1847DB68002B02D0521C92B2F7E734 +:1091200030BC70474FF0005090F8E2000449C2078D +:1091300001D0096800E04968002900D0084770475D +:1091400058081000B2F120030AD5C2F1200301FA39 +:1091500002F120FA03F300FA02F041EA030170473A +:1091600000FA03F14FF00000704710B54C1084EA8C +:10917000530404D54042C1F1000138BF491E1B42CF +:1091800004D55242C3F1000338BF5B1E00F0D9F88A +:1091900014F0804F04D04042C1F1000138BF491E95 +:1091A00014F0004F04D05242C3F1000338BF5B1EDD +:1091B00010BD032A40F2308010F0030C00F015803F +:1091C00011F8013BBCF1020F624498BF11F801CBCA +:1091D00000F8013B38BF11F8013BA2F1040298BF2F +:1091E00000F801CB38BF00F8013B11F0030300F099 +:1091F0002580083AC0F0088051F8043B083A51F83D +:1092000004CBA0E80810F5E7121D5CBF51F8043B41 +:1092100040F8043BAFF30080D20724BF11F8013BB4 +:1092200011F801CB48BF11F8012B24BF00F8013B16 +:1092300000F801CB48BF00F8012B704710B5203A69 +:10924000C0F00B80B1E81850203AA0E81850B1E8FF +:109250001850A0E81850BFF4F5AF5FEA027C24BFB5 +:10926000B1E81850A0E8185044BF18C918C0BDE8AC +:1092700010405FEA827C24BF51F8043B40F8043B75 +:1092800008BF7047D20728BF31F8023B48BF11F82A +:10929000012B28BF20F8023B48BF00F8012B704784 +:1092A00002F0FF0343EA032242EA024200F002B85E +:1092B0004FF000020429C0F0128010F0030C00F0FF +:1092C0001B80CCF1040CBCF1020F18BF00F8012B7D +:1092D000A8BF20F8022BA1EB0C0100F00DB85FEA4B +:1092E000C17C24BF00F8012B00F8012B48BF00F817 +:1092F000012B70474FF0000200B513469446964686 +:10930000203922BFA0E80C50A0E80C50B1F1200198 +:10931000BFF4F7AF090728BFA0E80C5048BF0CC046 +:109320005DF804EB890028BF40F8042B08BF7047A4 +:1093300048BF20F8022B11F0804F18BF00F8012B16 +:10934000704753EA020C00F069802DE9F04B4FF0B2 +:109350000006002B1FBFB3FA83F503FA05F424FAC5 +:1093600005F65E4012BF1643B2FA82F502FA05F422 +:10937000C5F120051EBF22FA05FC44EA0C04203585 +:1093800056EA044C4FEA144418BF641C4FF000081E +:109390004FF00009904271EB030C39D3002919BF3B +:1093A000B1FA81F701FA07F6B0FA80F700FA07F68A +:1093B000C7F120071EBF20FA07FC46EA0C0620373B +:1093C000B6FBF4FCA7EB0507103F07F01F0BCBF132 +:1093D00020060CFA0BFB2CFA06F644BFB346002617 +:1093E000202FA4BF5E464FF0000B5BEA060C08BFBF +:1093F0004FF0010B19EB0B09ABFB027C48EB0608A5 +:10940000C01B06FB02CC0BFB03CC71EB0C01C1E7CC +:109410000B46024641464846BDE8F08B13B54FF077 +:1094200000004FF00001AFF30080BDE81C40704722 +:1094300010B50446AFF300802046BDE81040E6F7C3 +:10944000EDBE704701491820ABBEFEE726000200C2 +:109450000149002008607047380500222DE9F041DD +:109460000F4F00244FF001084FF0005608FA04F0A7 +:10947000C5B296F82F0028420CD096F83900284241 +:1094800008D057F8240000B1804796F82F00A84371 +:1094900086F82F00641C062CE8DBBDE8F081000094 +:1094A000649310002DE9F0410F4F00244FF00108A4 +:1094B0004FF0005608FA04F0C5B296F82E00284284 +:1094C0000CD096F83800284208D057F8240000B194 +:1094D000804796F82E00A84386F82E00641C062CC0 +:1094E000E8DBBDE8F08100004493100001218140D9 +:1094F000C8B24FF0005191F83310014201D0012061 +:109500007047002070470000014901200860704743 +:109510003805002200487047510710000549044AE9 +:109520000A80054AC0E90021012101724172704799 +:109530006C550120EC0610000C970100074841789B +:1095400049B1807838B106488079012803D10548AF +:109550000078012800D0002070470000400710006C +:10956000A8511000180510000348417811B98078FF +:10957000002800D001207047400710000148007803 +:109580007047000010061000014800787047000086 +:1095900058051000064841788278C3781144027853 +:1095A00000791A441144081800D0012070470000C7 +:1095B000C005100070B5D0E900214C084FEA320315 +:1095C000961841EB010533432C4313430C43C0E988 +:1095D000003470BD01EB810100EBC1002930704700 +:1095E000024A1278514300EB410070478606100092 +:1095F00001EB810100EBC10029307047024A12786B +:10960000514300EB41007047860610001000000037 +:109610000400000001000000FF00FF00FF00000048 +:10962000000101010202000000000000C44A100015 +:1096300010501000EB140100020000002D15010075 +:1096400002000000DF16010002000000F914010012 +:10965000020000006B16010001000000BB150100B4 +:10966000070000008D16010001000000AF16010088 +:10967000010000005715010007000000C11401009F +:10968000711701006D170100891801006D170100A5 +:10969000191A01006D1701006D1701006D17010007 +:1096A0006D1701006D170100AF17010001000000E8 +:1096B000F7170100000000006D1701000000000016 +:1096C0000B18010001000000B518010001000000A6 +:1096D000D918010001000000FD1801000100000080 +:1096E00033190100040000000B1A01000100000002 +:1096F000451A010001000000991A01000100000054 +:10970000AF1A010002000000FF1A01000200000071 +:10971000BB1B010002000000711C010001000000E1 +:10972000B11C010001000000731B010002000000D9 +:10973000391C0100020000006D170100000000004C +:109740006D170100000000005F1A0100A51701005D +:10975000691A0100791A0100891A010086000201C4 +:1097600000A6020F0300A8020B0300000300000084 +:109770000000000003000000000000005300000093 +:10978000000000004300000000000000F3000000A3 +:1097900000000000E3000000000000005302000091 +:1097A000000000000000000005000000A876100086 +:1097B000000400005D3A000000000000020000000C +:1097C0000100000004000000A87A1000000400005E +:1097D000F94A000000000000020000000200000042 +:1097E00003000000A87E100000080000CD12010058 +:1097F0000000000002000000030000000200000062 +:10980000A8861000000200006D1D0100000000008D +:10981000020000000400000001000000A888100001 +:10982000800000002D140100000000000200000074 +:109830000000000001000000010000000100000025 +:109840000200000001000000030000000100000011 +:1098500004000000010000000500000001000000FD +:1098600000000000010000000200000003000000F2 +:10987000FB520100975201004B5B0100E35A0100CB +:10988000B36D0100374B0100A35301005554010093 +:10989000A35D01006F5C010001680100C96D01005A +:1098A0000004400010210000001F0100060000001D +:1098B00030000100000406000802500060020C0C99 +:1098C000000060020C300C1A31100F0F00002F0046 +:1098D0000100AA2C0100000003000000FFFF0300AC +:1098E0000000000018000000FFFFFFFF3F00000025 +:1098F0000000000000010000000000006002018084 +:109900000001000000000C000C000C000C0007011E +:1099100026261212110000000038003C203DD041E4 +:10992000EC4108421C423042444260427442884248 +:10993000A442000000000000000000000000000041 +:1099400000000020000101020102020301020203E3 +:1099500002030304000000001B0000802D000080B3 +:1099600036000000410000805A0000006C0000003A +:10997000770000809900008082000000B4000000A1 +:10998000AF000080D8000000C3000080F500008018 +:10999000EE000000290100803201000004010000F7 +:1099A0001F010080680100007301008045010080F4 +:1099B0005E010000B0010000AB0100809D0100804D +:1099C00086010000F1010080EA010000DC010000D6 +:1099D000C7010080490200805202000064020000BA +:1099E0007F02008008020000130200802502008030 +:1099F0003E020000D0020000CB020080FD02008089 +:109A0000E6020000910200808A020000BC02000011 +:109A1000A7020080600300007B0300804D030080EC +:109A200056030000210300803A0300000C030000ED +:109A300017030080F9030080E2030000D403000054 +:109A4000CF030080B8030000A303008095030080CB +:109A50008E0300008904008092040000A40400002A +:109A6000BF040080C8040000D3040080E504008027 +:109A7000FE040000100400000B0400803D04008080 +:109A800026040000510400804A0400007C04000009 +:109A900067040080A0050000BB0500808D050080E4 +:109AA00096050000E1050080FA050000CC050000E5 +:109AB000D70500803905008022050000140500004C +:109AC0000F050080780500006305008055050080C3 +:109AD0004E050000C0060000DB060080ED06008099 +:109AE000F6060000810600809A060000AC06000021 +:109AF000B706008059060080420600007406000088 +:109B00006F060080180600000306008035060080FE +:109B10002E060000E9070080F2070000C4070000DD +:109B2000DF070080A8070000B307008085070080DA +:109B30009E070000700700006B0700805D07008033 +:109B400046070000310700802A0700001C070000BC +:109B5000070700800909008012090000240900009D +:109B60003F09008048090000530900806509008012 +:109B70007E090000900900008B090080BD0900806B +:109B8000A6090000D1090080CA090000FC090000F4 +:109B9000E7090080200800003B0800800D080080D5 +:109BA00016080000610800807A0800004C080000D8 +:109BB00057080080B9080080A2080000940800003F +:109BC0008F080080F8080000E3080080D5080080B6 +:109BD000CE080000400B00005B0B00806D0B008086 +:109BE000760B0000010B00801A0B00002C0B00000C +:109BF000370B0080D90B0080C20B0000F40B000073 +:109C0000EF0B0080980B0000830B0080B50B0080E9 +:109C1000AE0B0000690A0080720A0000440A0000CE +:109C20005F0A0080280A0000330A0080050A0080CD +:109C30001E0A0000F00A0000EB0A0080DD0A008026 +:109C4000C60A0000B10A0080AA0A00009C0A0000AF +:109C5000870A0080800D00009B0D0080AD0D008004 +:109C6000B60D0000C10D0080DA0D0000EC0D000003 +:109C7000F70D0080190D0080020D0000340D00006A +:109C80002F0D0080580D0000430D0080750D0080E1 +:109C90006E0D0000A90C0080B20C0000840C0000C6 +:109CA0009F0C0080E80C0000F30C0080C50C0080C5 +:109CB000DE0C0000300C00002B0C00801D0C00801E +:109CC000060C0000710C00806A0C00005C0C0000A7 +:109CD000470C0080C90F0080D20F0000E40F000085 +:109CE000FF0F0080880F0000930F0080A50F0080F9 +:109CF000BE0F0000500F00004B0F00807D0F008052 +:109D0000660F0000110F00800A0F00003C0F0000DA +:109D1000270F0080E00E0000FB0E0080CD0E0080BB +:109D2000D60E0000A10E0080BA0E00008C0E0000BE +:109D3000970E0080790E0080620E0000540E000025 +:109D40004F0E0080380E0000230E0080150E00809C +:109D50000E0E0000349D0100000410006804000095 +:109D60001C010000609D010000FC1000400000008C +:109D700078010000609D0100680810001C8B000045 +:109D80009401000001FF014103FFFFFF01C4075DD3 +:109D9000F00120F052103206320F9A37089AE1088B +:109DA000035ED303AAFF0C590101150B5390D08A0F +:109DB00030B572B601230C4D2B600C4A002481B1E2 +:109DC00013604FF0005100F01F0081F86A0007484F +:109DD0001C38036001680029FCD114602C6062B655 +:109DE00030BD1460EDE70000C01B0022780D00229A +:109DF0007C78A72BF7020000838758D408FDFFFF6B +:109E00003E0037000103000037F1000000000000B1 +:109E1000FFFFFFFF03000000FFFF00000000000045 +:109E20002210230937040F23093704B8010000006A +:109E30000320200A88AA40014001E803C8009600D8 +:109E40009600960096007000700008B000B0000008 +:109E50001BAA0A04C8000000000000000000000067 +:109E60000D050F0A190FF900023200000000000072 +:109E700000000000000000000000000000000000E2 +:109E80000B013C0096009600D0010000000000008D +:109E900082000064000000FF0000000000000000DD +:109EA0001608000208000600000000A0504C260121 +:109EB00008001300000000008D05094F04002C006D +:109EC00002002B002660060000000000BBBB401F04 +:109ED000C80088880000ADA50D1F24002F002E00AB +:109EE000266006000000000026600600000000005A +:109EF000000126000000002606000000000000000F +:109F000000008D11084F0400300006002F004010A3 +:109F1000060000000100000000000000000000003A +:109F20000000E8650D1F10003400300060001700CD +:109F30001001100020009923000100000000000023 +:109F40000000000000000000000000000000000011 +:109F50000000000000000000000000000000000001 +:109F600011002C01000000000100000000000000B2 +:109F70000000B80B000000000E0000000000000010 +:109F800000000000000002000000000000000000CF +:109F90000E000000000000000000000000000200B1 +:109FA00000000000000000000000000000000200AF +:109FB000000064006400D000800CF00AD00000159E +:109FC000001250015001001500125001800CF00ADF +:109FD000D0000000000000000000000000000000B1 +:109FE000932A020A0F00011E180000000000300032 +:109FF00000000000FF0FFF0F10140A000000000017 +:10A000000B00C800000000D00F1490019001FF7FEA +:10A01000FF7FF40100000000056400030000000061 +:10A02000090096009600960096003C0064001E0011 +:10A0300002003C0064003C00C80000000000640016 +:10A040000102F4015E01002C012C010819C8000076 +:10A050000B030521010164006400600090013201DE +:10A060000000000000235802C800FF2C012000005F +:10A070000300640032002000140A84032800000456 +:10A080000000200006000500050000000600050095 +:10A0900005000000815C0200000100018200C80090 +:10A0A0000001080018001E0000010064403220007A +:10A0B0001E003200C8008813401F0564006400645D +:10A0C0000010004600FA96FAC800000000000000E8 +:10A0D0000000000000000000000000000000000080 +:10A0E0000000000084030C0E2000101250008200BB +:10A0F0006400000A6400000F00016000600000407E +:10A10000400000000000C800900150007C010032B7 +:10A1100001000000000000005600000000000000E8 +:10A12000000000000000000000000000000000002F +:10A1300002008C001E2803050202021311550000C4 +:10A140005E01C8000632001EF4010000000000009D +:10A1500041007800960032004000C8000000000076 +:10A160000000000000000000000000000000617B13 +:10A170000103AA00000210010002640006640064EA +:10A180000014001400107800320000211A000010A2 +:10A190000F01000A001482111400100004100400C2 +:10A1A000400000200030D8100064005194941888BA +:10A1B0006210003000100030000A001800053C0555 +:10A1C0003C033CD80532F80301030A960684C80014 +:10A1D0000FE80A0030000F5100000443C800C80017 +:10A1E0000A0A3C007800000A50003C0001640000AC +:10A1F000000000000000003C00960014E80300008E +:10A20000640003E8030000FA0003000000000000FF +:10A21000000000000000000000000000000000003E +:10A220000000000000000000110096001E28000041 +:10A2300000051E00FA000000500A051E06640A020E +:10A24000C8001E0300900164FA00C0000000000076 +:10A2500000000000000000000000000000000000FE +:10A2600000000102030400010203500150015001EB +:10A27000500100000000000000000000000000008D +:10A2800000000000000000000000000000000000CE +:10A2900000000000000000000000000000000000BE +:10A2A00000000000000000000000000000000000AE +:10A2B0005A5A5A5A5A5A5A5A5A5A5A5A5A5A5A0058 +:10A2C000000000000000000000000000000000008E +:10A2D00060595B5D5F5E5F60616263636364646479 +:10A2E0006464696A6B6B6C6C6D6D6F7070706E6CB2 +:10A2F0006C710000000000010C0C22222200000002 +:10A300000000000A00140032006400BF08F1080FCA +:10A3100009190923092309000000000A001400326A +:10A32000006400D303050423042D0437043704001C +:10A33000000000000000000000000000000000001D +:10A34000000000000009000B000D0019004200E3AE +:10A35000080E09130916091909230900000A00113A +:10A3600000180028004600E8030E041F04240429F6 +:10A37000043704000000000000000000000000009E +:10A3800000000000000000000000000000000000CD +:10A3900000000000000000000000000000000000BD +:10A3A00000000000000000000000000000000000AD +:10A3B000000000000000000000000000000000009D +:10A3C000000000000000000000000000000000008D +:10A3D000000000000000000000000000000000007D +:10A3E000000000000000000000000000000000006D +:10A3F000000000000000000000000000000000005D +:10A40000000000000000000000000000000000004C +:10A41000000000000000000000000000000000003C +:10A42000000000000000000000000000000000002C +:10A4300000000000000000000000000058004C0078 +:10A440004C004C00404C408C10CC40DC00005F00C5 +:10A450006100670070007D008E00A300BA00D50087 +:10A46000F300140137015C018401AD01D80104023D +:10A4700031025F028D02BA02E70214033F036A034E +:10A480009203B903DD03FF031F043B0454046A0471 +:10A490007D048C0497049F04A304A3049F049704E1 +:10A4A0008C047D046A0454043B041F04FF03DD0391 +:10A4B000B90392036A033F031403E702BA028D0251 +:10A4C0005F0231020402D801AD0184015C01370151 +:10A4D0001401F300D500BA00A3008E007D007000C7 +:10A4E000670061005F0094009800A500B900D600E5 +:10A4F000FB0027015A019401D30118026102AF0247 +:10A50000FF025103A503FA034E04A204F30442051B +:10A510008D05D505170653068A06B906E206030718 +:10A520001C072C07350735072C071C070307E20615 +:10A53000B9068A0653061706D5058D054205F304AC +:10A54000A2044E04FA03A5035103FF02AF02610205 +:10A550001802D30194015A012701FB00D600B9006B +:10A56000A500980094009A009F00AC00C200E00093 +:10A57000060135016A01A601E90130027D02CE0221 +:10A5800022037803D00328048004D8042D057F0516 +:10A59000CE0518065D069D06D60608073207540745 +:10A5A0006E0780078907890780076E0754073207FF +:10A5B0000807D6069D065D061806CE057F052D0503 +:10A5C000D80480042804D00378032203CE027D023D +:10A5D0003002E901A6016A0135010601E000C2006E +:10A5E000AC009F009A009400DD00AD01DE023E0445 +:10A5F0008D0594062307230794068D053E04DE028D +:10A60000AD01DD009400350037003B0043004D00F4 +:10A610005A006A007D009200A800C100DC00F7002B +:10A620001401320150016F018D01AB01C901E50137 +:10A6300000021A02320248025B026C027B028702AD +:10A6400090029602990299029602900287027B027A +:10A650006C025B02480232021A020002E501C901E3 +:10A66000AB018D016F01500132011401F700DC00D4 +:10A67000C100A80092007D006A005A004D0043000E +:10A680003B0037003500AE035203F902A402530227 +:10A690000602C001800147011601EE00CE00B6009F +:10A6A000A800A4000000000000000000000000005E +:10A6B0000000000000000000010001000100040192 +:10A6C00004050409040D0000FF03FE07FE07FE0752 +:10A6D000FE07FE07FE07FE07FE07FE07FE07FE0752 +:10A6E000FE07FF07FF07FF07FF070000000000004D +:10A6F000000000000000000000000000000000005A +:10A700000000000000000000000000000000000049 +:10A710000000000000000000000000000000000039 +:10A720000000000000000000000000000000000029 +:10A730000000000000000000000000000000000019 +:10A740000000000000000000000000030507080CE6 +:10A750000D0F0F0F0E0E0E0D0D0D0A08000000005C +:10A7600000000000000000000000000000000000E9 +:10A7700000000000000000000000000000000000D9 +:10A7800000000000000000000000000000000000C9 +:10A790000000000000000000000000000302500064 +:10A7A00050004A0150204E0B0132001405000A20CF +:10A7B0001405F80002013C0001020F0F2323083C9E +:10A7C000083C40F805050A0A0105050F1400E86574 +:10A7D0000D1F100034003000600017001001100041 +:10A7E000080099E3000000000000000000000000E5 +:10A7F00000000000000000006400000000000000F5 +:10A8000000000A0014050000005028502814B02051 +:10A81000FF00D0000614142A3A4000323200146EB1 +:10A820006E471A38000000010F1E00200100FAB622 +:10A8300001810265073508461046100A1215081AEC +:10A8400005050000000000E920021F10002500257A +:10A85000005000240070018001100055000000002D +:10A8600000000000000000000000000000000000E8 +:10A8700000000000888800F799990000000100009E +:10A880000000100710961E000F6414000F00020253 +:10A890000302030396C8FF00000000000000000050 +:10A8A00000000000012800640AE8036404000000BE +:10A8B00000000001000100010001080018810000F3 +:10A8C0000000041000000108000E0000000000005D +:10A8D0000000000000000200AA00E8440D1F104024 +:10A8E0004C004C00600028000101010120005503CC +:10A8F000200500000080004000983AC800000D626A +:10A90000640064001414F401F401F401F401000083 +:10A910000014000000002C01320300880000000039 +:10A92000000000000000000000000000040800001B +:10A930003404F400700036000F000A000400000028 +:10A94000000004000A000F0036007000F400340418 +:10A9500000000000000000000000000000000000F7 +:10A9600000000000000000000000000000000000E7 +:10A9700000000000000000000000008B10960000A6 +:10A9800000010A2C010414002C010000002C01100D +:10A990001E0FC800032800FFCCFFDFA36854433517 +:10A9A0002B221B15120E0B090706050400000000E0 +:10A9B000000000FFFFFFFFFFFFFFFFFFFFFF84031B +:10A9C0009001FA000F073223190000000000000078 +:04A9D000B09513002B +:00000001FF diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c index 469666df91da..44b54a3ae951 100644 --- a/fs/binfmt_elf.c +++ b/fs/binfmt_elf.c @@ -681,7 +681,8 @@ static int load_elf_binary(struct linux_binprm *bprm) struct file *interpreter = NULL; /* to shut gcc up */ unsigned long load_addr = 0, load_bias = 0; int load_addr_set = 0; - char * elf_interpreter = NULL; + char elf_interpreter[PATH_MAX] __aligned(sizeof(long)); + bool interp_present = false; unsigned long error; struct elf_phdr *elf_ppnt, *elf_phdata, *interp_elf_phdata = NULL; unsigned long elf_bss, elf_brk; @@ -696,32 +697,26 @@ static int load_elf_binary(struct linux_binprm *bprm) struct { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; - } *loc; + } loc; struct arch_elf_state arch_state = INIT_ARCH_ELF_STATE; loff_t pos; - loc = kmalloc(sizeof(*loc), GFP_KERNEL); - if (!loc) { - retval = -ENOMEM; - goto out_ret; - } - /* Get the exec-header */ - loc->elf_ex = *((struct elfhdr *)bprm->buf); + loc.elf_ex = *((struct elfhdr *)bprm->buf); retval = -ENOEXEC; /* First of all, some simple consistency checks */ - if (memcmp(loc->elf_ex.e_ident, ELFMAG, SELFMAG) != 0) + if (memcmp(loc.elf_ex.e_ident, ELFMAG, SELFMAG) != 0) goto out; - if (loc->elf_ex.e_type != ET_EXEC && loc->elf_ex.e_type != ET_DYN) + if (loc.elf_ex.e_type != ET_EXEC && loc.elf_ex.e_type != ET_DYN) goto out; - if (!elf_check_arch(&loc->elf_ex)) + if (!elf_check_arch(&loc.elf_ex)) goto out; if (!bprm->file->f_op->mmap) goto out; - elf_phdata = load_elf_phdrs(&loc->elf_ex, bprm->file); + elf_phdata = load_elf_phdrs(&loc.elf_ex, bprm->file); if (!elf_phdata) goto out; @@ -734,7 +729,7 @@ static int load_elf_binary(struct linux_binprm *bprm) start_data = 0; end_data = 0; - for (i = 0; i < loc->elf_ex.e_phnum; i++) { + for (i = 0; i < loc.elf_ex.e_phnum; i++) { if (elf_ppnt->p_type == PT_INTERP) { /* This is the program interpreter used for * shared libraries - for now assume that this @@ -745,29 +740,24 @@ static int load_elf_binary(struct linux_binprm *bprm) elf_ppnt->p_filesz < 2) goto out_free_ph; - retval = -ENOMEM; - elf_interpreter = kmalloc(elf_ppnt->p_filesz, - GFP_KERNEL); - if (!elf_interpreter) - goto out_free_ph; - + interp_present = true; pos = elf_ppnt->p_offset; retval = kernel_read(bprm->file, elf_interpreter, elf_ppnt->p_filesz, &pos); if (retval != elf_ppnt->p_filesz) { if (retval >= 0) retval = -EIO; - goto out_free_interp; + goto out_free_ph; } /* make sure path is NULL terminated */ retval = -ENOEXEC; if (elf_interpreter[elf_ppnt->p_filesz - 1] != '\0') - goto out_free_interp; + goto out_free_ph; interpreter = open_exec(elf_interpreter); retval = PTR_ERR(interpreter); if (IS_ERR(interpreter)) - goto out_free_interp; + goto out_free_ph; /* * If the binary is not readable then enforce @@ -778,9 +768,9 @@ static int load_elf_binary(struct linux_binprm *bprm) /* Get the exec headers */ pos = 0; - retval = kernel_read(interpreter, &loc->interp_elf_ex, - sizeof(loc->interp_elf_ex), &pos); - if (retval != sizeof(loc->interp_elf_ex)) { + retval = kernel_read(interpreter, &loc.interp_elf_ex, + sizeof(loc.interp_elf_ex), &pos); + if (retval != sizeof(loc.interp_elf_ex)) { if (retval >= 0) retval = -EIO; goto out_free_dentry; @@ -792,7 +782,7 @@ static int load_elf_binary(struct linux_binprm *bprm) } elf_ppnt = elf_phdata; - for (i = 0; i < loc->elf_ex.e_phnum; i++, elf_ppnt++) + for (i = 0; i < loc.elf_ex.e_phnum; i++, elf_ppnt++) switch (elf_ppnt->p_type) { case PT_GNU_STACK: if (elf_ppnt->p_flags & PF_X) @@ -802,7 +792,7 @@ static int load_elf_binary(struct linux_binprm *bprm) break; case PT_LOPROC ... PT_HIPROC: - retval = arch_elf_pt_proc(&loc->elf_ex, elf_ppnt, + retval = arch_elf_pt_proc(&loc.elf_ex, elf_ppnt, bprm->file, false, &arch_state); if (retval) @@ -811,27 +801,27 @@ static int load_elf_binary(struct linux_binprm *bprm) } /* Some simple consistency checks for the interpreter */ - if (elf_interpreter) { + if (interp_present) { retval = -ELIBBAD; /* Not an ELF interpreter */ - if (memcmp(loc->interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) + if (memcmp(loc.interp_elf_ex.e_ident, ELFMAG, SELFMAG) != 0) goto out_free_dentry; /* Verify the interpreter has a valid arch */ - if (!elf_check_arch(&loc->interp_elf_ex)) + if (!elf_check_arch(&loc.interp_elf_ex)) goto out_free_dentry; /* Load the interpreter program headers */ - interp_elf_phdata = load_elf_phdrs(&loc->interp_elf_ex, + interp_elf_phdata = load_elf_phdrs(&loc.interp_elf_ex, interpreter); if (!interp_elf_phdata) goto out_free_dentry; /* Pass PT_LOPROC..PT_HIPROC headers to arch code */ elf_ppnt = interp_elf_phdata; - for (i = 0; i < loc->interp_elf_ex.e_phnum; i++, elf_ppnt++) + for (i = 0; i < loc.interp_elf_ex.e_phnum; i++, elf_ppnt++) switch (elf_ppnt->p_type) { case PT_LOPROC ... PT_HIPROC: - retval = arch_elf_pt_proc(&loc->interp_elf_ex, + retval = arch_elf_pt_proc(&loc.interp_elf_ex, elf_ppnt, interpreter, true, &arch_state); if (retval) @@ -845,8 +835,8 @@ static int load_elf_binary(struct linux_binprm *bprm) * still possible to return an error to the code that invoked * the exec syscall. */ - retval = arch_check_elf(&loc->elf_ex, - !!interpreter, &loc->interp_elf_ex, + retval = arch_check_elf(&loc.elf_ex, + !!interpreter, &loc.interp_elf_ex, &arch_state); if (retval) goto out_free_dentry; @@ -858,8 +848,8 @@ static int load_elf_binary(struct linux_binprm *bprm) /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality. */ - SET_PERSONALITY2(loc->elf_ex, &arch_state); - if (elf_read_implies_exec(loc->elf_ex, executable_stack)) + SET_PERSONALITY2(loc.elf_ex, &arch_state); + if (elf_read_implies_exec(loc.elf_ex, executable_stack)) current->personality |= READ_IMPLIES_EXEC; if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) @@ -880,7 +870,7 @@ static int load_elf_binary(struct linux_binprm *bprm) /* Now we do a little grungy work by mmapping the ELF image into the correct location in memory. */ for(i = 0, elf_ppnt = elf_phdata; - i < loc->elf_ex.e_phnum; i++, elf_ppnt++) { + i < loc.elf_ex.e_phnum; i++, elf_ppnt++) { int elf_prot = 0, elf_flags; unsigned long k, vaddr; unsigned long total_size = 0; @@ -929,9 +919,9 @@ static int load_elf_binary(struct linux_binprm *bprm) * If we are loading ET_EXEC or we have already performed * the ET_DYN load_addr calculations, proceed normally. */ - if (loc->elf_ex.e_type == ET_EXEC || load_addr_set) { + if (loc.elf_ex.e_type == ET_EXEC || load_addr_set) { elf_flags |= MAP_FIXED; - } else if (loc->elf_ex.e_type == ET_DYN) { + } else if (loc.elf_ex.e_type == ET_DYN) { /* * This logic is run once for the first LOAD Program * Header for ET_DYN binaries to calculate the @@ -962,7 +952,7 @@ static int load_elf_binary(struct linux_binprm *bprm) * independently randomized mmap region (0 load_bias * without MAP_FIXED). */ - if (elf_interpreter) { + if (interp_present) { load_bias = ELF_ET_DYN_BASE; if (current->flags & PF_RANDOMIZE) load_bias += arch_mmap_rnd(); @@ -980,7 +970,7 @@ static int load_elf_binary(struct linux_binprm *bprm) load_bias = ELF_PAGESTART(load_bias - vaddr); total_size = total_mapping_size(elf_phdata, - loc->elf_ex.e_phnum); + loc.elf_ex.e_phnum); if (!total_size) { retval = -EINVAL; goto out_free_dentry; @@ -998,7 +988,7 @@ static int load_elf_binary(struct linux_binprm *bprm) if (!load_addr_set) { load_addr_set = 1; load_addr = (elf_ppnt->p_vaddr - elf_ppnt->p_offset); - if (loc->elf_ex.e_type == ET_DYN) { + if (loc.elf_ex.e_type == ET_DYN) { load_bias += error - ELF_PAGESTART(load_bias + vaddr); load_addr += load_bias; @@ -1039,7 +1029,7 @@ static int load_elf_binary(struct linux_binprm *bprm) } } - loc->elf_ex.e_entry += load_bias; + loc.elf_ex.e_entry += load_bias; elf_bss += load_bias; elf_brk += load_bias; start_code += load_bias; @@ -1060,10 +1050,10 @@ static int load_elf_binary(struct linux_binprm *bprm) goto out_free_dentry; } - if (elf_interpreter) { + if (interp_present) { unsigned long interp_map_addr = 0; - elf_entry = load_elf_interp(&loc->interp_elf_ex, + elf_entry = load_elf_interp(&loc.interp_elf_ex, interpreter, &interp_map_addr, load_bias, interp_elf_phdata); @@ -1073,7 +1063,7 @@ static int load_elf_binary(struct linux_binprm *bprm) * adjustment */ interp_load_addr = elf_entry; - elf_entry += loc->interp_elf_ex.e_entry; + elf_entry += loc.interp_elf_ex.e_entry; } if (BAD_ADDR(elf_entry)) { retval = IS_ERR((void *)elf_entry) ? @@ -1084,9 +1074,8 @@ static int load_elf_binary(struct linux_binprm *bprm) allow_write_access(interpreter); fput(interpreter); - kfree(elf_interpreter); } else { - elf_entry = loc->elf_ex.e_entry; + elf_entry = loc.elf_ex.e_entry; if (BAD_ADDR(elf_entry)) { retval = -EINVAL; goto out_free_dentry; @@ -1099,12 +1088,12 @@ static int load_elf_binary(struct linux_binprm *bprm) set_binfmt(&elf_format); #ifdef ARCH_HAS_SETUP_ADDITIONAL_PAGES - retval = arch_setup_additional_pages(bprm, !!elf_interpreter); + retval = arch_setup_additional_pages(bprm, interp_present); if (retval < 0) goto out; #endif /* ARCH_HAS_SETUP_ADDITIONAL_PAGES */ - retval = create_elf_tables(bprm, &loc->elf_ex, + retval = create_elf_tables(bprm, &loc.elf_ex, load_addr, interp_load_addr); if (retval < 0) goto out; @@ -1149,8 +1138,6 @@ static int load_elf_binary(struct linux_binprm *bprm) start_thread(regs, elf_entry, bprm->p); retval = 0; out: - kfree(loc); -out_ret: return retval; /* error cleanup */ @@ -1159,8 +1146,6 @@ static int load_elf_binary(struct linux_binprm *bprm) allow_write_access(interpreter); if (interpreter) fput(interpreter); -out_free_interp: - kfree(elf_interpreter); out_free_ph: kfree(elf_phdata); goto out; diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c index 1792999eec91..0b22abe4be8b 100644 --- a/fs/ext4/mballoc.c +++ b/fs/ext4/mballoc.c @@ -2916,18 +2916,10 @@ int __init ext4_init_mballoc(void) if (ext4_pspace_cachep == NULL) return -ENOMEM; - ext4_ac_cachep = KMEM_CACHE(ext4_allocation_context, - SLAB_RECLAIM_ACCOUNT); - if (ext4_ac_cachep == NULL) { - kmem_cache_destroy(ext4_pspace_cachep); - return -ENOMEM; - } - ext4_free_data_cachep = KMEM_CACHE(ext4_free_data, SLAB_RECLAIM_ACCOUNT); if (ext4_free_data_cachep == NULL) { kmem_cache_destroy(ext4_pspace_cachep); - kmem_cache_destroy(ext4_ac_cachep); return -ENOMEM; } return 0; @@ -4498,7 +4490,7 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, struct ext4_allocation_request *ar, int *errp) { int freed; - struct ext4_allocation_context *ac = NULL; + struct ext4_allocation_context ac; struct ext4_sb_info *sbi; struct super_block *sb; ext4_fsblk_t block = 0; @@ -4551,52 +4543,46 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, } } - ac = kmem_cache_zalloc(ext4_ac_cachep, GFP_NOFS); - if (!ac) { - ar->len = 0; - *errp = -ENOMEM; - goto out; - } - - *errp = ext4_mb_initialize_context(ac, ar); + memset(&ac, 0, sizeof(ac)); + *errp = ext4_mb_initialize_context(&ac, ar); if (*errp) { ar->len = 0; goto out; } - ac->ac_op = EXT4_MB_HISTORY_PREALLOC; - if (!ext4_mb_use_preallocated(ac)) { - ac->ac_op = EXT4_MB_HISTORY_ALLOC; - ext4_mb_normalize_request(ac, ar); + ac.ac_op = EXT4_MB_HISTORY_PREALLOC; + if (!ext4_mb_use_preallocated(&ac)) { + ac.ac_op = EXT4_MB_HISTORY_ALLOC; + ext4_mb_normalize_request(&ac, ar); repeat: /* allocate space in core */ - *errp = ext4_mb_regular_allocator(ac); + *errp = ext4_mb_regular_allocator(&ac); if (*errp) goto discard_and_exit; /* as we've just preallocated more space than * user requested originally, we store allocated * space in a special descriptor */ - if (ac->ac_status == AC_STATUS_FOUND && - ac->ac_o_ex.fe_len < ac->ac_b_ex.fe_len) - *errp = ext4_mb_new_preallocation(ac); + if (ac.ac_status == AC_STATUS_FOUND && + ac.ac_o_ex.fe_len < ac.ac_b_ex.fe_len) + *errp = ext4_mb_new_preallocation(&ac); if (*errp) { discard_and_exit: - ext4_discard_allocated_blocks(ac); + ext4_discard_allocated_blocks(&ac); goto errout; } } - if (likely(ac->ac_status == AC_STATUS_FOUND)) { - *errp = ext4_mb_mark_diskspace_used(ac, handle, reserv_clstrs); + if (likely(ac.ac_status == AC_STATUS_FOUND)) { + *errp = ext4_mb_mark_diskspace_used(&ac, handle, reserv_clstrs); if (*errp) { - ext4_discard_allocated_blocks(ac); + ext4_discard_allocated_blocks(&ac); goto errout; } else { - block = ext4_grp_offs_to_block(sb, &ac->ac_b_ex); - ar->len = ac->ac_b_ex.fe_len; + block = ext4_grp_offs_to_block(sb, &ac.ac_b_ex); + ar->len = ac.ac_b_ex.fe_len; } } else { - freed = ext4_mb_discard_preallocations(sb, ac->ac_o_ex.fe_len); + freed = ext4_mb_discard_preallocations(sb, ac.ac_o_ex.fe_len); if (freed) goto repeat; *errp = -ENOSPC; @@ -4604,14 +4590,12 @@ ext4_fsblk_t ext4_mb_new_blocks(handle_t *handle, errout: if (*errp) { - ac->ac_b_ex.fe_len = 0; + ac.ac_b_ex.fe_len = 0; ar->len = 0; - ext4_mb_show_ac(ac); + ext4_mb_show_ac(&ac); } - ext4_mb_release_context(ac); + ext4_mb_release_context(&ac); out: - if (ac) - kmem_cache_free(ext4_ac_cachep, ac); if (inquota && ar->len < inquota) dquot_free_block(ar->inode, EXT4_C2B(sbi, inquota - ar->len)); if (!ar->len) { diff --git a/fs/namespace.c b/fs/namespace.c index 2416d562ce82..26a2cb140d5d 100644 --- a/fs/namespace.c +++ b/fs/namespace.c @@ -2887,9 +2887,9 @@ long do_mount(const char *dev_name, const char __user *dir_name, if (retval) goto dput_out; - /* Default to relatime unless overriden */ - if (!(flags & MS_NOATIME)) - mnt_flags |= MNT_RELATIME; + /* Default to noatime unless overriden */ + if (!(flags & MS_RELATIME)) + mnt_flags |= MNT_NOATIME; /* Separate the per-mountpoint flags */ if (flags & MS_NOSUID) diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c index a9e28ae8091f..aae2998833bd 100644 --- a/fs/sdcardfs/lookup.c +++ b/fs/sdcardfs/lookup.c @@ -234,9 +234,12 @@ static int sdcardfs_name_match(struct dir_context *ctx, const char *name, struct qstr candidate = QSTR_INIT(name, namelen); if (qstr_case_eq(buf->to_find, &candidate)) { - memcpy(buf->name, name, namelen); - buf->name[namelen] = 0; buf->found = true; + buf->name = kmalloc(namelen + 1, GFP_KERNEL); + if (buf->name) { + memcpy(buf->name, name, namelen); + buf->name[namelen] = '\0'; + } return 1; } return 0; @@ -285,33 +288,34 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, struct sdcardfs_name_data buffer = { .ctx.actor = sdcardfs_name_match, .to_find = name, - .name = __getname(), .found = false, }; - if (!buffer.name) { - err = -ENOMEM; - goto out; - } file = dentry_open(lower_parent_path, O_RDONLY, cred); if (IS_ERR(file)) { err = PTR_ERR(file); - goto put_name; + goto err; } + err = iterate_dir(file, &buffer.ctx); fput(file); if (err) - goto put_name; + goto err; + + if (buffer.found) { + if (!buffer.name) { + err = -ENOMEM; + goto out; + } - if (buffer.found) err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, buffer.name, 0, &lower_path); - else + kfree(buffer.name); + } else { err = -ENOENT; -put_name: - __putname(buffer.name); + } } /* no error: handle positive dentries */ @@ -359,6 +363,7 @@ static struct dentry *__sdcardfs_lookup(struct dentry *dentry, * We don't consider ENOENT an error, and we want to return a * negative dentry. */ +err: if (err && err != -ENOENT) goto out; diff --git a/include/asm-generic/bitops/atomic.h b/include/asm-generic/bitops/atomic.h index 04deffaf5f7d..dd90c9792909 100644 --- a/include/asm-generic/bitops/atomic.h +++ b/include/asm-generic/bitops/atomic.h @@ -2,189 +2,67 @@ #ifndef _ASM_GENERIC_BITOPS_ATOMIC_H_ #define _ASM_GENERIC_BITOPS_ATOMIC_H_ -#include -#include - -#ifdef CONFIG_SMP -#include -#include /* we use L1_CACHE_BYTES */ - -/* Use an array of spinlocks for our atomic_ts. - * Hash function to index into a different SPINLOCK. - * Since "a" is usually an address, use one spinlock per cacheline. - */ -# define ATOMIC_HASH_SIZE 4 -# define ATOMIC_HASH(a) (&(__atomic_hash[ (((unsigned long) a)/L1_CACHE_BYTES) & (ATOMIC_HASH_SIZE-1) ])) - -extern arch_spinlock_t __atomic_hash[ATOMIC_HASH_SIZE] __lock_aligned; - -/* Can't use raw_spin_lock_irq because of #include problems, so - * this is the substitute */ -#define _atomic_spin_lock_irqsave(l,f) do { \ - arch_spinlock_t *s = ATOMIC_HASH(l); \ - local_irq_save(f); \ - arch_spin_lock(s); \ -} while(0) - -#define _atomic_spin_unlock_irqrestore(l,f) do { \ - arch_spinlock_t *s = ATOMIC_HASH(l); \ - arch_spin_unlock(s); \ - local_irq_restore(f); \ -} while(0) - - -#else -# define _atomic_spin_lock_irqsave(l,f) do { local_irq_save(f); } while (0) -# define _atomic_spin_unlock_irqrestore(l,f) do { local_irq_restore(f); } while (0) -#endif +#include +#include +#include /* - * NMI events can occur at any time, including when interrupts have been - * disabled by *_irqsave(). So you can get NMI events occurring while a - * *_bit function is holding a spin lock. If the NMI handler also wants - * to do bit manipulation (and they do) then you can get a deadlock - * between the original caller of *_bit() and the NMI handler. - * - * by Keith Owens + * Implementation of atomic bitops using atomic-fetch ops. + * See Documentation/atomic_bitops.txt for details. */ -/** - * set_bit - Atomically set a bit in memory - * @nr: the bit to set - * @addr: the address to start counting from - * - * This function is atomic and may not be reordered. See __set_bit() - * if you do not require the atomic guarantees. - * - * Note: there are no guarantees that this function will not be reordered - * on non x86 architectures, so if you are writing portable code, - * make sure not to rely on its reordering guarantees. - * - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static inline void set_bit(int nr, volatile unsigned long *addr) +static inline void set_bit(unsigned int nr, volatile unsigned long *p) { - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - *p |= mask; - _atomic_spin_unlock_irqrestore(p, flags); + p += BIT_WORD(nr); + atomic_long_or(BIT_MASK(nr), (atomic_long_t *)p); } -/** - * clear_bit - Clears a bit in memory - * @nr: Bit to clear - * @addr: Address to start counting from - * - * clear_bit() is atomic and may not be reordered. However, it does - * not contain a memory barrier, so if it is used for locking purposes, - * you should call smp_mb__before_atomic() and/or smp_mb__after_atomic() - * in order to ensure changes are visible on other processors. - */ -static inline void clear_bit(int nr, volatile unsigned long *addr) +static inline void clear_bit(unsigned int nr, volatile unsigned long *p) { - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - *p &= ~mask; - _atomic_spin_unlock_irqrestore(p, flags); + p += BIT_WORD(nr); + atomic_long_andnot(BIT_MASK(nr), (atomic_long_t *)p); } -/** - * change_bit - Toggle a bit in memory - * @nr: Bit to change - * @addr: Address to start counting from - * - * change_bit() is atomic and may not be reordered. It may be - * reordered on other architectures than x86. - * Note that @nr may be almost arbitrarily large; this function is not - * restricted to acting on a single-word quantity. - */ -static inline void change_bit(int nr, volatile unsigned long *addr) +static inline void change_bit(unsigned int nr, volatile unsigned long *p) { - unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - *p ^= mask; - _atomic_spin_unlock_irqrestore(p, flags); + p += BIT_WORD(nr); + atomic_long_xor(BIT_MASK(nr), (atomic_long_t *)p); } -/** - * test_and_set_bit - Set a bit and return its old value - * @nr: Bit to set - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It may be reordered on other architectures than x86. - * It also implies a memory barrier. - */ -static inline int test_and_set_bit(int nr, volatile unsigned long *addr) +static inline int test_and_set_bit(unsigned int nr, volatile unsigned long *p) { + long old; unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - unsigned long flags; - _atomic_spin_lock_irqsave(p, flags); - old = *p; - *p = old | mask; - _atomic_spin_unlock_irqrestore(p, flags); + p += BIT_WORD(nr); + if (READ_ONCE(*p) & mask) + return 1; - return (old & mask) != 0; + old = atomic_long_fetch_or(mask, (atomic_long_t *)p); + return !!(old & mask); } -/** - * test_and_clear_bit - Clear a bit and return its old value - * @nr: Bit to clear - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It can be reorderdered on other architectures other than x86. - * It also implies a memory barrier. - */ -static inline int test_and_clear_bit(int nr, volatile unsigned long *addr) +static inline int test_and_clear_bit(unsigned int nr, volatile unsigned long *p) { + long old; unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - unsigned long flags; - _atomic_spin_lock_irqsave(p, flags); - old = *p; - *p = old & ~mask; - _atomic_spin_unlock_irqrestore(p, flags); + p += BIT_WORD(nr); + if (!(READ_ONCE(*p) & mask)) + return 0; - return (old & mask) != 0; + old = atomic_long_fetch_andnot(mask, (atomic_long_t *)p); + return !!(old & mask); } -/** - * test_and_change_bit - Change a bit and return its old value - * @nr: Bit to change - * @addr: Address to count from - * - * This operation is atomic and cannot be reordered. - * It also implies a memory barrier. - */ -static inline int test_and_change_bit(int nr, volatile unsigned long *addr) +static inline int test_and_change_bit(unsigned int nr, volatile unsigned long *p) { + long old; unsigned long mask = BIT_MASK(nr); - unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr); - unsigned long old; - unsigned long flags; - - _atomic_spin_lock_irqsave(p, flags); - old = *p; - *p = old ^ mask; - _atomic_spin_unlock_irqrestore(p, flags); - return (old & mask) != 0; + p += BIT_WORD(nr); + old = atomic_long_fetch_xor(mask, (atomic_long_t *)p); + return !!(old & mask); } #endif /* _ASM_GENERIC_BITOPS_ATOMIC_H */ diff --git a/include/drm/drm_mipi_dsi.h b/include/drm/drm_mipi_dsi.h index 328f232f33ee..5cca02a40294 100644 --- a/include/drm/drm_mipi_dsi.h +++ b/include/drm/drm_mipi_dsi.h @@ -284,6 +284,8 @@ int mipi_dsi_dcs_set_pixel_format(struct mipi_dsi_device *dsi, u8 format); int mipi_dsi_dcs_set_tear_scanline(struct mipi_dsi_device *dsi, u16 scanline); int mipi_dsi_dcs_set_display_brightness(struct mipi_dsi_device *dsi, u16 brightness); +int mipi_dsi_dcs_set_display_brightness_ss(struct mipi_dsi_device *dsi, + u16 brightness); int mipi_dsi_dcs_get_display_brightness(struct mipi_dsi_device *dsi, u16 *brightness); diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h index 2d228d9e6a61..add4379a0793 100644 --- a/include/linux/blkdev.h +++ b/include/linux/blkdev.h @@ -655,10 +655,9 @@ struct request_queue { #define QUEUE_FLAG_QUIESCED 28 /* queue has been quiesced */ #define QUEUE_FLAG_INLINECRYPT 29 /* inline encryption support */ -#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ +#define QUEUE_FLAG_DEFAULT ((1 << QUEUE_FLAG_NONROT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ - (1 << QUEUE_FLAG_SAME_COMP) | \ - (1 << QUEUE_FLAG_ADD_RANDOM)) + (1 << QUEUE_FLAG_SAME_COMP)) #define QUEUE_FLAG_MQ_DEFAULT ((1 << QUEUE_FLAG_IO_STAT) | \ (1 << QUEUE_FLAG_STACKABLE) | \ diff --git a/include/linux/cpu_cooling.h b/include/linux/cpu_cooling.h index f85fa59e6009..07a3f9a69245 100644 --- a/include/linux/cpu_cooling.h +++ b/include/linux/cpu_cooling.h @@ -54,6 +54,7 @@ struct thermal_cooling_device * cpufreq_platform_cooling_register(const struct cpumask *clip_cpus, struct cpu_cooling_ops *ops); +void cpu_limits_set_level(unsigned int cpu, unsigned int max_freq); /** * of_cpufreq_cooling_register - create cpufreq cooling device based on DT. * @np: a valid struct device_node to the cooling device device tree node. diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index ed0ff1538049..01420e4d71df 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -430,6 +430,7 @@ static inline void cpufreq_resume(void) {} #define CPUFREQ_ADJUST (0) #define CPUFREQ_NOTIFY (1) #define CPUFREQ_INCOMPATIBLE (6) +#define CPUFREQ_THERMAL (2) #ifdef CONFIG_CPU_FREQ int cpufreq_register_notifier(struct notifier_block *nb, unsigned int list); diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index d06bf77400f1..50956451b6d0 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -28,6 +28,7 @@ struct gpio_keys_button { int wakeup; int debounce_interval; bool can_disable; + bool level_trigger; int value; unsigned int irq; }; diff --git a/include/linux/i2c.h b/include/linux/i2c.h index d501d3956f13..e55d85ba1772 100644 --- a/include/linux/i2c.h +++ b/include/linux/i2c.h @@ -682,6 +682,7 @@ i2c_unlock_adapter(struct i2c_adapter *adapter) #define I2C_CLIENT_SLAVE 0x20 /* we are the slave */ #define I2C_CLIENT_HOST_NOTIFY 0x40 /* We want to use I2C host notify */ #define I2C_CLIENT_WAKE 0x80 /* for board_info; true iff can wake */ +#define I2C_CLIENT_ASYNC_SUSPEND 0x100 /* async suspend is supported */ #define I2C_CLIENT_SCCB 0x9000 /* Use Omnivision SCCB protocol */ /* Must match I2C_M_STOP|IGNORE_NAK */ diff --git a/include/linux/input/qpnp-power-on.h b/include/linux/input/qpnp-power-on.h index 4fa954a9b1de..f233df254279 100644 --- a/include/linux/input/qpnp-power-on.h +++ b/include/linux/input/qpnp-power-on.h @@ -61,6 +61,8 @@ enum pon_restart_reason { PON_RESTART_REASON_DMVERITY_CORRUPTED = 0x04, PON_RESTART_REASON_DMVERITY_ENFORCE = 0x05, PON_RESTART_REASON_KEYS_CLEAR = 0x06, + PON_RESTART_REASON_NORMAL = 0x20, + PON_RESTART_REASON_PANIC = 0x21, }; #ifdef CONFIG_INPUT_QPNP_POWER_ON diff --git a/include/linux/mfd/spk-id.h b/include/linux/mfd/spk-id.h new file mode 100644 index 000000000000..3e99afd03007 --- /dev/null +++ b/include/linux/mfd/spk-id.h @@ -0,0 +1,32 @@ +/* Copyright (c) 2016, The Linux Foundation. All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 and + * only 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. + */ + +#ifndef __SPK_ID_H_ +#define __SPK_ID_H_ + +#include +#include + +#define PIN_PULL_DOWN 0 +#define PIN_PULL_UP 1 +#define PIN_FLOAT 2 + +#define VENDOR_ID_NONE 0 +#define VENDOR_ID_AAC 1 +#define VENDOR_ID_SSI 2 +#define VENDOR_ID_GOER 3 + +#define VENDOR_ID_UNKNOWN 4 + +extern int spk_id_get_pin_3state(struct device_node *np); + +#endif diff --git a/include/linux/msm_drm_notify.h b/include/linux/msm_drm_notify.h index 924ba852c99c..4f9b32662ad5 100644 --- a/include/linux/msm_drm_notify.h +++ b/include/linux/msm_drm_notify.h @@ -23,6 +23,10 @@ enum { /* panel: power on */ MSM_DRM_BLANK_UNBLANK, + MSM_DRM_BLANK_LP1, + MSM_DRM_BLANK_LP2, + MSM_DRM_BLANK_STANDBY, + MSM_DRM_BLANK_SUSPEND, /* panel: power off */ MSM_DRM_BLANK_POWERDOWN, }; @@ -42,4 +46,5 @@ struct msm_drm_notifier { int msm_drm_register_client(struct notifier_block *nb); int msm_drm_unregister_client(struct notifier_block *nb); +int msm_drm_notifier_call_chain(unsigned long val, void *v); #endif diff --git a/include/linux/msm_gsi.h b/include/linux/msm_gsi.h index 32a3e67d5916..04c16703e206 100644 --- a/include/linux/msm_gsi.h +++ b/include/linux/msm_gsi.h @@ -1095,7 +1095,7 @@ int gsi_alloc_evt_ring(struct gsi_evt_ring_props *props, unsigned long dev_hdl, * @Return gsi_status */ int gsi_write_evt_ring_scratch(unsigned long evt_ring_hdl, - union __packed gsi_evt_scratch val); + union gsi_evt_scratch val); /** * gsi_dealloc_evt_ring - Peripheral should call this function to @@ -1222,7 +1222,7 @@ int gsi_alloc_channel(struct gsi_chan_props *props, unsigned long dev_hdl, * @Return gsi_status */ int gsi_write_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch val); + union gsi_channel_scratch val); /** * gsi_write_channel_scratch3_reg - Peripheral should call this function to @@ -1235,7 +1235,7 @@ int gsi_write_channel_scratch(unsigned long chan_hdl, * @Return gsi_status */ int gsi_write_channel_scratch3_reg(unsigned long chan_hdl, - union __packed gsi_wdi_channel_scratch3_reg val); + union gsi_wdi_channel_scratch3_reg val); /** * gsi_write_wdi3_channel_scratch2_reg - Peripheral should call this function @@ -1261,7 +1261,7 @@ int gsi_write_wdi3_channel_scratch2_reg(unsigned long chan_hdl, * @Return gsi_status */ int gsi_read_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch *val); + union gsi_channel_scratch *val); /** * gsi_read_wdi3_channel_scratch2_reg - Peripheral should call this function to @@ -1289,7 +1289,7 @@ int gsi_read_wdi3_channel_scratch2_reg(unsigned long chan_hdl, * @Return gsi_status */ int gsi_update_mhi_channel_scratch(unsigned long chan_hdl, - struct __packed gsi_mhi_channel_scratch mscr); + struct gsi_mhi_channel_scratch mscr); /** * gsi_start_channel - Peripheral should call this function to @@ -1677,7 +1677,7 @@ static inline int gsi_alloc_evt_ring(struct gsi_evt_ring_props *props, } static inline int gsi_write_evt_ring_scratch(unsigned long evt_ring_hdl, - union __packed gsi_evt_scratch val) + union gsi_evt_scratch val) { return -GSI_STATUS_UNSUPPORTED_OP; } @@ -1717,24 +1717,24 @@ static inline int gsi_alloc_channel(struct gsi_chan_props *props, } static inline int gsi_write_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch val) + union gsi_channel_scratch val) { return -GSI_STATUS_UNSUPPORTED_OP; } static inline int gsi_write_channel_scratch3_reg(unsigned long chan_hdl, - union __packed gsi_wdi_channel_scratch3_reg val) + union gsi_wdi_channel_scratch3_reg val) { return -GSI_STATUS_UNSUPPORTED_OP; } static inline int gsi_read_channel_scratch(unsigned long chan_hdl, - union __packed gsi_channel_scratch *val) + union gsi_channel_scratch *val) { return -GSI_STATUS_UNSUPPORTED_OP; } static inline int gsi_update_mhi_channel_scratch(unsigned long chan_hdl, - struct __packed gsi_mhi_channel_scratch mscr) + struct gsi_mhi_channel_scratch mscr) { return -GSI_STATUS_UNSUPPORTED_OP; } diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h index 891ef068d66f..f98aafd77dc9 100644 --- a/include/linux/power_supply.h +++ b/include/linux/power_supply.h @@ -231,6 +231,8 @@ enum power_supply_property { POWER_SUPPLY_PROP_CHARGE_ENABLED, POWER_SUPPLY_PROP_SET_SHIP_MODE, POWER_SUPPLY_PROP_REAL_TYPE, + POWER_SUPPLY_PROP_HVDCP3_TYPE, + POWER_SUPPLY_PROP_QUICK_CHARGE_TYPE, POWER_SUPPLY_PROP_CHARGE_NOW_RAW, POWER_SUPPLY_PROP_CHARGE_NOW_ERROR, POWER_SUPPLY_PROP_CAPACITY_RAW, @@ -285,6 +287,7 @@ enum power_supply_property { POWER_SUPPLY_PROP_TYPEC_SRC_RP, POWER_SUPPLY_PROP_PD_ALLOWED, POWER_SUPPLY_PROP_PD_ACTIVE, + POWER_SUPPLY_PROP_PD_AUTHENTICATION, POWER_SUPPLY_PROP_PD_IN_HARD_RESET, POWER_SUPPLY_PROP_PD_CURRENT_MAX, POWER_SUPPLY_PROP_PD_USB_SUSPEND_SUPPORTED, @@ -308,9 +311,16 @@ enum power_supply_property { POWER_SUPPLY_PROP_PD_VOLTAGE_MAX, POWER_SUPPLY_PROP_PD_VOLTAGE_MIN, POWER_SUPPLY_PROP_SDP_CURRENT_MAX, + POWER_SUPPLY_PROP_DC_THERMAL_LEVELS, POWER_SUPPLY_PROP_CONNECTOR_TYPE, POWER_SUPPLY_PROP_PARALLEL_BATFET_MODE, POWER_SUPPLY_PROP_PARALLEL_FCC_MAX, + POWER_SUPPLY_PROP_WIRELESS_VERSION, + POWER_SUPPLY_PROP_SIGNAL_STRENGTH, + POWER_SUPPLY_PROP_WIRELESS_CP_EN, + POWER_SUPPLY_PROP_WIRELESS_POWER_GOOD_EN, + POWER_SUPPLY_PROP_WIRELESS_WAKELOCK, + POWER_SUPPLY_PROP_TX_ADAPTER, POWER_SUPPLY_PROP_MIN_ICL, POWER_SUPPLY_PROP_MOISTURE_DETECTED, POWER_SUPPLY_PROP_BATT_PROFILE_VERSION, @@ -326,6 +336,9 @@ enum power_supply_property { POWER_SUPPLY_PROP_FORCE_RECHARGE, POWER_SUPPLY_PROP_FCC_STEPPER_ENABLE, POWER_SUPPLY_PROP_TOGGLE_STAT, + POWER_SUPPLY_PROP_TYPE_RECHECK, + POWER_SUPPLY_PROP_LIQUID_DETECTION, + POWER_SUPPLY_PROP_DYNAMIC_FV_ENABLED, POWER_SUPPLY_PROP_MAIN_FCC_MAX, POWER_SUPPLY_PROP_FG_RESET, POWER_SUPPLY_PROP_QC_OPTI_DISABLE, @@ -394,6 +407,7 @@ enum power_supply_type { POWER_SUPPLY_TYPE_UFP, /* Type-C UFP */ POWER_SUPPLY_TYPE_DFP, /* Type-C DFP */ POWER_SUPPLY_TYPE_CHARGE_PUMP, /* Charge Pump */ + POWER_SUPPLY_TYPE_ZIMI_CAR_POWER, /* Zimi Car chargr */ }; /* Indicates USB Type-C CC connection status */ diff --git a/include/linux/usb/gadget_configfs.h b/include/linux/usb/gadget_configfs.h index d61aebd68128..1799d5300176 100644 --- a/include/linux/usb/gadget_configfs.h +++ b/include/linux/usb/gadget_configfs.h @@ -7,6 +7,10 @@ int check_user_usb_string(const char *name, struct usb_gadget_strings *stringtab_dev); +#define VNAME(var) (#var) +/*default usbserial number, defined in init.qcom.usb.sh*/ +#define DEFAULT_USB_SERIAL_NUMBER "1234567" + #define GS_STRINGS_W(__struct, __name) \ static ssize_t __struct##_##__name##_store(struct config_item *item, \ const char *page, size_t len) \ @@ -14,6 +18,16 @@ static ssize_t __struct##_##__name##_store(struct config_item *item, \ struct __struct *gs = to_##__struct(item); \ int ret; \ \ + if ((strncmp(VNAME(__name), "serialnumber", 12) == 0) \ + && (gs->__name != NULL) \ + && (strncmp(page, DEFAULT_USB_SERIAL_NUMBER, 7) == 0)) \ + { \ + /*if serialnumber is not null, don't set it to*/ \ + /* default serialnumber */ \ + pr_err("usb serialnumber is not NULL, don't set to %s\n", page); \ + return -EINVAL; \ + } \ + \ ret = usb_string_copy(page, &gs->__name); \ if (ret) \ return ret; \ diff --git a/include/soc/qcom/socinfo.h b/include/soc/qcom/socinfo.h index 0a1816507e8e..fd6a5c196b41 100644 --- a/include/soc/qcom/socinfo.h +++ b/include/soc/qcom/socinfo.h @@ -218,6 +218,11 @@ enum pmic_model { PMIC_MODEL_UNKNOWN = 0xFFFFFFFF }; +#define HARDWARE_PLATFORM_UNKNOWN 0 +#define HARDWARE_PLATFORM_CEPHEUS 1 + +uint32_t get_hw_version_platform(void); + enum msm_cpu socinfo_get_msm_cpu(void); uint32_t socinfo_get_id(void); uint32_t socinfo_get_version(void); diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 385c141d5433..2873a2ac7da8 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -417,6 +417,7 @@ #define BTN_WHEEL 0x150 #define BTN_GEAR_DOWN 0x150 #define BTN_GEAR_UP 0x151 +#define BTN_INFO 0x152 #define KEY_OK 0x160 #define KEY_SELECT 0x161 @@ -638,6 +639,12 @@ #define KEY_UNMUTE 0x274 #define KEY_FASTREVERSE 0x275 #define KEY_SLOWREVERSE 0x276 + +/* + * AI KEY + */ +#define KEY_AI 0x2b1 + /* * Control a data application associated with the currently viewed channel, * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.) diff --git a/include/uapi/linux/msm_ipa.h b/include/uapi/linux/msm_ipa.h index 55bae183af1c..cf76540991e7 100644 --- a/include/uapi/linux/msm_ipa.h +++ b/include/uapi/linux/msm_ipa.h @@ -2016,8 +2016,6 @@ struct ipa_ioc_ext_intf_prop { uint8_t is_xlat_rule; uint32_t rule_id; uint8_t is_rule_hashable; -#define IPA_V6_UL_WL_FIREWALL_HANDLE - uint8_t replicate_needed; }; /** diff --git a/include/uapi/media/cam_defs.h b/include/uapi/media/cam_defs.h index 0fa3777ee7a5..640e7a8707a8 100644 --- a/include/uapi/media/cam_defs.h +++ b/include/uapi/media/cam_defs.h @@ -26,6 +26,9 @@ #define CAM_EXT_OPCODE_BASE 0x200 #define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) +#define CAM_UPDATE_REG (CAM_EXT_OPCODE_BASE + 0x2) +#define CAM_READ_REG (CAM_EXT_OPCODE_BASE + 0x3) + /* camera handle type */ #define CAM_HANDLE_USER_POINTER 1 #define CAM_HANDLE_MEM_HANDLE 2 diff --git a/include/uapi/media/cam_req_mgr.h b/include/uapi/media/cam_req_mgr.h index bdc1cb94c28c..2c7d4299ac63 100644 --- a/include/uapi/media/cam_req_mgr.h +++ b/include/uapi/media/cam_req_mgr.h @@ -35,7 +35,7 @@ * Max handles supported by cam_req_mgr * It includes both session and device handles */ -#define CAM_REQ_MGR_MAX_HANDLES 64 +#define CAM_REQ_MGR_MAX_HANDLES 128 #define CAM_REQ_MGR_MAX_HANDLES_V2 128 #define MAX_LINKS_PER_SESSION 2 diff --git a/include/uapi/media/cam_sensor.h b/include/uapi/media/cam_sensor.h index 8fc180b7b632..7ef78ba894fd 100644 --- a/include/uapi/media/cam_sensor.h +++ b/include/uapi/media/cam_sensor.h @@ -370,6 +370,7 @@ struct cam_sensor_acquire_dev { uint32_t handle_type; uint32_t reserved; uint64_t info_handle; + uint32_t operation_mode;//XIAOMI: libin16 add for face unlock } __attribute__((packed)); /** diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 406aeb8c5f9a..557cb03cbbb6 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c @@ -191,6 +191,8 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask, if (!chip || !chip->irq_set_affinity) return -EINVAL; + /* IRQs only run on the first CPU in the affinity mask; reflect that */ + mask = cpumask_of(cpumask_first(mask)); ret = chip->irq_set_affinity(data, mask, force); switch (ret) { case IRQ_SET_MASK_OK: diff --git a/kernel/power/qos.c b/kernel/power/qos.c index 15de2fb554ab..06d7e74703fe 100644 --- a/kernel/power/qos.c +++ b/kernel/power/qos.c @@ -54,7 +54,7 @@ /* * locking rule: all changes to constraints or notifiers lists * or pm_qos_object list and pm_qos_objects need to happen with pm_qos_lock - * held, taken with _irqsave. One lock to rule them all + * held. One lock to rule them all */ struct pm_qos_object { struct pm_qos_constraints *constraints; @@ -199,7 +199,6 @@ static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) struct pm_qos_constraints *c; struct pm_qos_request *req; char *type; - unsigned long flags; int tot_reqs = 0; int active_reqs = 0; @@ -214,7 +213,7 @@ static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) } /* Lock to ensure we have a snapshot */ - spin_lock_irqsave(&pm_qos_lock, flags); + spin_lock(&pm_qos_lock); if (plist_head_empty(&c->list)) { seq_puts(s, "Empty!\n"); goto out; @@ -250,7 +249,7 @@ static int pm_qos_dbg_show_requests(struct seq_file *s, void *unused) type, pm_qos_get_value(c), active_reqs, tot_reqs); out: - spin_unlock_irqrestore(&pm_qos_lock, flags); + spin_unlock(&pm_qos_lock); return 0; } @@ -315,12 +314,11 @@ static inline void pm_qos_set_value_for_cpus(struct pm_qos_constraints *c, int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, enum pm_qos_req_action action, int value) { - unsigned long flags; int prev_value, curr_value, new_value; struct cpumask cpus; int ret; - spin_lock_irqsave(&pm_qos_lock, flags); + spin_lock(&pm_qos_lock); prev_value = pm_qos_get_value(c); if (value == PM_QOS_DEFAULT_VALUE) new_value = c->default_value; @@ -352,10 +350,6 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, pm_qos_set_value(c, curr_value); pm_qos_set_value_for_cpus(c, &cpus); - spin_unlock_irqrestore(&pm_qos_lock, flags); - - trace_pm_qos_update_target(action, prev_value, curr_value); - /* * if cpu mask bits are set, call the notifier call chain * to update the new qos restriction for the cores @@ -369,6 +363,11 @@ int pm_qos_update_target(struct pm_qos_constraints *c, struct plist_node *node, } else { ret = 0; } + + spin_unlock(&pm_qos_lock); + + trace_pm_qos_update_target(action, prev_value, curr_value); + return ret; } @@ -404,10 +403,9 @@ bool pm_qos_update_flags(struct pm_qos_flags *pqf, struct pm_qos_flags_request *req, enum pm_qos_req_action action, s32 val) { - unsigned long irqflags; s32 prev_value, curr_value; - spin_lock_irqsave(&pm_qos_lock, irqflags); + spin_lock(&pm_qos_lock); prev_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags; @@ -430,7 +428,7 @@ bool pm_qos_update_flags(struct pm_qos_flags *pqf, curr_value = list_empty(&pqf->list) ? 0 : pqf->effective_flags; - spin_unlock_irqrestore(&pm_qos_lock, irqflags); + spin_unlock(&pm_qos_lock); trace_pm_qos_update_flags(action, prev_value, curr_value); return prev_value != curr_value; @@ -465,12 +463,11 @@ EXPORT_SYMBOL_GPL(pm_qos_request_active); int pm_qos_request_for_cpumask(int pm_qos_class, struct cpumask *mask) { - unsigned long irqflags; int cpu; struct pm_qos_constraints *c = NULL; int val; - spin_lock_irqsave(&pm_qos_lock, irqflags); + spin_lock(&pm_qos_lock); c = pm_qos_array[pm_qos_class]->constraints; val = c->default_value; @@ -489,7 +486,7 @@ int pm_qos_request_for_cpumask(int pm_qos_class, struct cpumask *mask) break; } } - spin_unlock_irqrestore(&pm_qos_lock, irqflags); + spin_unlock(&pm_qos_lock); return val; } @@ -524,7 +521,6 @@ static void pm_qos_work_fn(struct work_struct *work) #ifdef CONFIG_SMP static void pm_qos_irq_release(struct kref *ref) { - unsigned long flags; struct irq_affinity_notify *notify = container_of(ref, struct irq_affinity_notify, kref); struct pm_qos_request *req = container_of(notify, @@ -532,9 +528,9 @@ static void pm_qos_irq_release(struct kref *ref) struct pm_qos_constraints *c = pm_qos_array[req->pm_qos_class]->constraints; - spin_lock_irqsave(&pm_qos_lock, flags); + spin_lock(&pm_qos_lock); cpumask_setall(&req->cpus_affine); - spin_unlock_irqrestore(&pm_qos_lock, flags); + spin_unlock(&pm_qos_lock); pm_qos_update_target(c, &req->node, PM_QOS_UPDATE_REQ, c->default_value); @@ -543,7 +539,6 @@ static void pm_qos_irq_release(struct kref *ref) static void pm_qos_irq_notify(struct irq_affinity_notify *notify, const cpumask_t *unused_mask) { - unsigned long flags; struct pm_qos_request *req = container_of(notify, struct pm_qos_request, irq_notify); struct pm_qos_constraints *c = @@ -553,13 +548,13 @@ static void pm_qos_irq_notify(struct irq_affinity_notify *notify, irq_data_get_effective_affinity_mask(&desc->irq_data); bool affinity_changed = false; - spin_lock_irqsave(&pm_qos_lock, flags); + spin_lock(&pm_qos_lock); if (!cpumask_equal(&req->cpus_affine, new_affinity)) { cpumask_copy(&req->cpus_affine, new_affinity); affinity_changed = true; } - spin_unlock_irqrestore(&pm_qos_lock, flags); + spin_unlock(&pm_qos_lock); if (affinity_changed) pm_qos_update_target(c, &req->node, PM_QOS_UPDATE_REQ, @@ -861,7 +856,6 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf, size_t count, loff_t *f_pos) { s32 value; - unsigned long flags; struct pm_qos_request *req = filp->private_data; if (!req) @@ -869,9 +863,9 @@ static ssize_t pm_qos_power_read(struct file *filp, char __user *buf, if (!pm_qos_request_active(req)) return -EINVAL; - spin_lock_irqsave(&pm_qos_lock, flags); + spin_lock(&pm_qos_lock); value = pm_qos_get_value(pm_qos_array[req->pm_qos_class]->constraints); - spin_unlock_irqrestore(&pm_qos_lock, flags); + spin_unlock(&pm_qos_lock); return simple_read_from_buffer(buf, count, f_pos, &value, sizeof(s32)); } diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 692506c8fe1a..8a5800f0a451 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c @@ -4224,7 +4224,7 @@ void __init rcu_init(void) } /* Create workqueue for expedited GPs and for Tree SRCU. */ - rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_MEM_RECLAIM, 0); + rcu_gp_wq = alloc_workqueue("rcu_gp", WQ_POWER_EFFICIENT | WQ_MEM_RECLAIM, 0); WARN_ON(!rcu_gp_wq); } diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index f3795c00b66c..14127d9cfeea 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -254,7 +254,7 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time, } else { if (use_pelt()) sg_policy->work_in_progress = true; - irq_work_queue(&sg_policy->irq_work); + sched_irq_work_queue(&sg_policy->irq_work); } } diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h index 66929d24c576..d434c4056e7f 100644 --- a/kernel/sched/sched.h +++ b/kernel/sched/sched.h @@ -3136,3 +3136,13 @@ struct sched_avg_stats { int nr_max; }; extern void sched_get_nr_running_avg(struct sched_avg_stats *stats); + +#ifdef CONFIG_SMP +static inline void sched_irq_work_queue(struct irq_work *work) +{ + if (likely(cpu_online(raw_smp_processor_id()))) + irq_work_queue(work); + else + irq_work_queue_on(work, cpumask_any(cpu_online_mask)); +} +#endif diff --git a/kernel/sched/walt.c b/kernel/sched/walt.c index 39fe4bd35bdb..274da0d5ee16 100644 --- a/kernel/sched/walt.c +++ b/kernel/sched/walt.c @@ -874,7 +874,7 @@ void fixup_busy_time(struct task_struct *p, int new_cpu) if (!same_freq_domain(new_cpu, task_cpu(p))) { src_rq->notif_pending = true; dest_rq->notif_pending = true; - irq_work_queue(&walt_migration_irq_work); + sched_irq_work_queue(&walt_migration_irq_work); } if (is_ed_enabled()) { @@ -1956,7 +1956,7 @@ static inline void run_walt_irq_work(u64 old_window_start, struct rq *rq) result = atomic64_cmpxchg(&walt_irq_work_lastq_ws, old_window_start, rq->window_start); if (result == old_window_start) - irq_work_queue(&walt_cpufreq_irq_work); + sched_irq_work_queue(&walt_cpufreq_irq_work); } /* Reflect task activity on its demand and cpu's busy time statistics */ diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c8f8754af943..5e5e0c3639c5 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c @@ -98,6 +98,9 @@ #if defined(CONFIG_SYSCTL) /* External variables not in a header file. */ +#ifdef CONFIG_USB +extern int deny_new_usb; +#endif extern int suid_dumpable; #ifdef CONFIG_COREDUMP extern int core_uses_pid; @@ -1013,6 +1016,17 @@ static struct ctl_table kern_table[] = { .extra1 = &zero, .extra2 = &two, }, +#endif +#ifdef CONFIG_USB + { + .procname = "deny_new_usb", + .data = &deny_new_usb, + .maxlen = sizeof(int), + .mode = 0644, + .proc_handler = proc_dointvec_minmax_sysadmin, + .extra1 = &zero, + .extra2 = &one, + }, #endif { .procname = "ngroups_max", diff --git a/lib/Makefile b/lib/Makefile index 76eb6a7602c0..33766f4ecfaf 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -26,6 +26,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \ earlycpio.o seq_buf.o siphash.o \ nmi_backtrace.o nodemask.o win_minmax.o +CFLAGS_kobject_uevent.o += -Wframe-larger-than=3072 lib-$(CONFIG_MMU) += ioremap.o lib-$(CONFIG_SMP) += cpumask.o lib-$(CONFIG_DMA_NOOP_OPS) += dma-noop.o diff --git a/lib/kobject_uevent.c b/lib/kobject_uevent.c index f237a09a5862..1d4c78a213d5 100644 --- a/lib/kobject_uevent.c +++ b/lib/kobject_uevent.c @@ -327,7 +327,7 @@ static void zap_modalias_env(struct kobj_uevent_env *env) int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, char *envp_ext[]) { - struct kobj_uevent_env *env; + struct kobj_uevent_env env; const char *action_string = kobject_actions[action]; const char *devpath = NULL; const char *subsystem; @@ -386,11 +386,6 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, return 0; } - /* environment buffer */ - env = kzalloc(sizeof(struct kobj_uevent_env), GFP_KERNEL); - if (!env) - return -ENOMEM; - /* complete object path */ devpath = kobject_get_path(kobj, GFP_KERNEL); if (!devpath) { @@ -398,21 +393,23 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, goto exit; } + memset(&env, 0, sizeof(env)); + /* default keys */ - retval = add_uevent_var(env, "ACTION=%s", action_string); + retval = add_uevent_var(&env, "ACTION=%s", action_string); if (retval) goto exit; - retval = add_uevent_var(env, "DEVPATH=%s", devpath); + retval = add_uevent_var(&env, "DEVPATH=%s", devpath); if (retval) goto exit; - retval = add_uevent_var(env, "SUBSYSTEM=%s", subsystem); + retval = add_uevent_var(&env, "SUBSYSTEM=%s", subsystem); if (retval) goto exit; /* keys passed in from the caller */ if (envp_ext) { for (i = 0; envp_ext[i]; i++) { - retval = add_uevent_var(env, "%s", envp_ext[i]); + retval = add_uevent_var(&env, "%s", envp_ext[i]); if (retval) goto exit; } @@ -420,7 +417,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* let the kset specific function add its stuff */ if (uevent_ops && uevent_ops->uevent) { - retval = uevent_ops->uevent(kset, kobj, env); + retval = uevent_ops->uevent(kset, kobj, &env); if (retval) { pr_debug("kobject: '%s' (%p): %s: uevent() returned " "%d\n", kobject_name(kobj), kobj, @@ -446,7 +443,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, break; case KOBJ_UNBIND: - zap_modalias_env(env); + zap_modalias_env(&env); break; default: @@ -455,7 +452,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, mutex_lock(&uevent_sock_mutex); /* we will send an event, so request a new sequence number */ - retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum); + retval = add_uevent_var(&env, "SEQNUM=%llu", (unsigned long long)++uevent_seqnum); if (retval) { mutex_unlock(&uevent_sock_mutex); goto exit; @@ -473,7 +470,7 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, /* allocate message with the maximum possible size */ len = strlen(action_string) + strlen(devpath) + 2; - skb = alloc_skb(len + env->buflen, GFP_KERNEL); + skb = alloc_skb(len + env.buflen, GFP_KERNEL); if (skb) { char *scratch; @@ -482,10 +479,10 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, sprintf(scratch, "%s@%s", action_string, devpath); /* copy keys to our continuous event payload buffer */ - for (i = 0; i < env->envp_idx; i++) { - len = strlen(env->envp[i]) + 1; + for (i = 0; i < env.envp_idx; i++) { + len = strlen(env.envp[i]) + 1; scratch = skb_put(skb, len); - strcpy(scratch, env->envp[i]); + strcpy(scratch, env.envp[i]); } NETLINK_CB(skb).dst_group = 1; @@ -507,31 +504,28 @@ int kobject_uevent_env(struct kobject *kobj, enum kobject_action action, if (uevent_helper[0] && !kobj_usermode_filter(kobj)) { struct subprocess_info *info; - retval = add_uevent_var(env, "HOME=/"); + retval = add_uevent_var(&env, "HOME=/"); if (retval) goto exit; - retval = add_uevent_var(env, + retval = add_uevent_var(&env, "PATH=/sbin:/bin:/usr/sbin:/usr/bin"); if (retval) goto exit; - retval = init_uevent_argv(env, subsystem); + retval = init_uevent_argv(&env, subsystem); if (retval) goto exit; retval = -ENOMEM; - info = call_usermodehelper_setup(env->argv[0], env->argv, - env->envp, GFP_KERNEL, - NULL, cleanup_uevent_env, env); - if (info) { + info = call_usermodehelper_setup(env.argv[0], env.argv, + env.envp, GFP_KERNEL, + NULL, cleanup_uevent_env, &env); + if (info) retval = call_usermodehelper_exec(info, UMH_NO_WAIT); - env = NULL; /* freed by cleanup_uevent_env */ - } } #endif exit: kfree(devpath); - kfree(env); return retval; } EXPORT_SYMBOL_GPL(kobject_uevent_env); diff --git a/lib/scatterlist.c b/lib/scatterlist.c index be7b4dd6b68d..3e218e29c798 100644 --- a/lib/scatterlist.c +++ b/lib/scatterlist.c @@ -163,30 +163,12 @@ EXPORT_SYMBOL(sg_init_one); */ static struct scatterlist *sg_kmalloc(unsigned int nents, gfp_t gfp_mask) { - if (nents == SG_MAX_SINGLE_ALLOC) { - /* - * Kmemleak doesn't track page allocations as they are not - * commonly used (in a raw form) for kernel data structures. - * As we chain together a list of pages and then a normal - * kmalloc (tracked by kmemleak), in order to for that last - * allocation not to become decoupled (and thus a - * false-positive) we need to inform kmemleak of all the - * intermediate allocations. - */ - void *ptr = (void *) __get_free_page(gfp_mask); - kmemleak_alloc(ptr, PAGE_SIZE, 1, gfp_mask); - return ptr; - } else - return kmalloc(nents * sizeof(struct scatterlist), gfp_mask); + return kmalloc(nents * sizeof(struct scatterlist), gfp_mask); } static void sg_kfree(struct scatterlist *sg, unsigned int nents) { - if (nents == SG_MAX_SINGLE_ALLOC) { - kmemleak_free(sg); - free_page((unsigned long) sg); - } else - kfree(sg); + kfree(sg); } /** diff --git a/mm/slab_common.c b/mm/slab_common.c index f6764cf162b8..0c3f529090e1 100644 --- a/mm/slab_common.c +++ b/mm/slab_common.c @@ -462,6 +462,9 @@ kmem_cache_create(const char *name, size_t size, size_t align, */ flags &= CACHE_CREATE_MASK; + /* Embrace davem */ + flags |= SLAB_HWCACHE_ALIGN; + s = __kmem_cache_alias(name, size, align, flags, ctor); if (s) goto out_unlock; diff --git a/net/Kconfig b/net/Kconfig index 549d3c9766f6..4534bb4dd92a 100644 --- a/net/Kconfig +++ b/net/Kconfig @@ -182,7 +182,7 @@ config BRIDGE_NETFILTER depends on BRIDGE depends on NETFILTER && INET depends on NETFILTER_ADVANCED - default m + default n ---help--- Enabling this option will let arptables resp. iptables see bridged ARP resp. IP traffic. If you want a bridging firewall, you probably diff --git a/net/ipv4/Kconfig b/net/ipv4/Kconfig index f48fe6fc7e8c..3b823d868411 100644 --- a/net/ipv4/Kconfig +++ b/net/ipv4/Kconfig @@ -478,7 +478,7 @@ if TCP_CONG_ADVANCED config TCP_CONG_BIC tristate "Binary Increase Congestion (BIC) control" - default m + default n ---help--- BIC-TCP is a sender-side only change that ensures a linear RTT fairness under large windows while offering both scalability and @@ -500,7 +500,7 @@ config TCP_CONG_CUBIC config TCP_CONG_WESTWOOD tristate "TCP Westwood+" - default m + default n ---help--- TCP Westwood+ is a sender-side only modification of the TCP Reno protocol stack that optimizes the performance of TCP congestion @@ -514,7 +514,7 @@ config TCP_CONG_WESTWOOD config TCP_CONG_HTCP tristate "H-TCP" - default m + default n ---help--- H-TCP is a send-side only modifications of the TCP Reno protocol stack that optimizes the performance of TCP diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 86156b462a9d..231124fe10b0 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -367,26 +367,22 @@ printf "%08x\n" $$dec_size | \ quiet_cmd_bzip2 = BZIP2 $@ cmd_bzip2 = (cat $(filter-out FORCE,$^) | \ - bzip2 -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) + bzip2 -9 || (rm -f $@ ; false) # Lzma # --------------------------------------------------------------------------- quiet_cmd_lzma = LZMA $@ cmd_lzma = (cat $(filter-out FORCE,$^) | \ - lzma -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) + lzma -9 || (rm -f $@ ; false) quiet_cmd_lzo = LZO $@ cmd_lzo = (cat $(filter-out FORCE,$^) | \ - lzop -9 && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) + lzop -9 || (rm -f $@ ; false) quiet_cmd_lz4 = LZ4 $@ cmd_lz4 = (cat $(filter-out FORCE,$^) | \ - lz4c -l -c1 stdin stdout && $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) + lz4c -l -c1 stdin stdout || (rm -f $@ ; false) # U-Boot mkimage # --------------------------------------------------------------------------- @@ -431,9 +427,7 @@ quiet_cmd_uimage = UIMAGE $(UIMAGE_OUT) # decompression mode. A BCJ filter isn't used either. quiet_cmd_xzkern = XZKERN $@ cmd_xzkern = (cat $(filter-out FORCE,$^) | \ - sh $(srctree)/scripts/xz_wrap.sh && \ - $(call size_append, $(filter-out FORCE,$^))) > $@ || \ - (rm -f $@ ; false) + sh $(srctree)/scripts/xz_wrap.sh || (rm -f $@ ; false) quiet_cmd_xzmisc = XZMISC $@ cmd_xzmisc = (cat $(filter-out FORCE,$^) | \ diff --git a/sound/core/control_compat.c b/sound/core/control_compat.c index 507fd5210c1c..ee150f8988a9 100644 --- a/sound/core/control_compat.c +++ b/sound/core/control_compat.c @@ -94,55 +94,52 @@ struct snd_ctl_elem_info32 { static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, struct snd_ctl_elem_info32 __user *data32) { - struct snd_ctl_elem_info *data; + struct snd_ctl_elem_info data; int err; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (! data) - return -ENOMEM; - + memset(&data, 0, sizeof(data)); err = -EFAULT; /* copy id */ - if (copy_from_user(&data->id, &data32->id, sizeof(data->id))) + if (copy_from_user(&data.id, &data32->id, sizeof(data.id))) goto error; /* we need to copy the item index. * hope this doesn't break anything.. */ - if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) + if (get_user(data.value.enumerated.item, &data32->value.enumerated.item)) goto error; err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; - err = snd_ctl_elem_info(ctl, data); + err = snd_ctl_elem_info(ctl, &data); if (err < 0) goto error; /* restore info to 32bit */ err = -EFAULT; /* id, type, access, count */ - if (copy_to_user(&data32->id, &data->id, sizeof(data->id)) || - copy_to_user(&data32->type, &data->type, 3 * sizeof(u32))) + if (copy_to_user(&data32->id, &data.id, sizeof(data.id)) || + copy_to_user(&data32->type, &data.type, 3 * sizeof(u32))) goto error; - if (put_user(data->owner, &data32->owner)) + if (put_user(data.owner, &data32->owner)) goto error; - switch (data->type) { + switch (data.type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: case SNDRV_CTL_ELEM_TYPE_INTEGER: - if (put_user(data->value.integer.min, &data32->value.integer.min) || - put_user(data->value.integer.max, &data32->value.integer.max) || - put_user(data->value.integer.step, &data32->value.integer.step)) + if (put_user(data.value.integer.min, &data32->value.integer.min) || + put_user(data.value.integer.max, &data32->value.integer.max) || + put_user(data.value.integer.step, &data32->value.integer.step)) goto error; break; case SNDRV_CTL_ELEM_TYPE_INTEGER64: if (copy_to_user(&data32->value.integer64, - &data->value.integer64, - sizeof(data->value.integer64))) + &data.value.integer64, + sizeof(data.value.integer64))) goto error; break; case SNDRV_CTL_ELEM_TYPE_ENUMERATED: if (copy_to_user(&data32->value.enumerated, - &data->value.enumerated, - sizeof(data->value.enumerated))) + &data.value.enumerated, + sizeof(data.value.enumerated))) goto error; break; default: @@ -150,7 +147,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, } err = 0; error: - kfree(data); return err; } @@ -187,7 +183,7 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, int *countp) { struct snd_kcontrol *kctl; - struct snd_ctl_elem_info *info; + struct snd_ctl_elem_info info; int err; down_read(&card->controls_rwsem); @@ -196,19 +192,13 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id, up_read(&card->controls_rwsem); return -ENOENT; } - info = kzalloc(sizeof(*info), GFP_KERNEL); - if (info == NULL) { - up_read(&card->controls_rwsem); - return -ENOMEM; - } - info->id = *id; - err = kctl->info(kctl, info); + info = (typeof(info)){ .id = *id }; + err = kctl->info(kctl, &info); up_read(&card->controls_rwsem); if (err >= 0) { - err = info->type; - *countp = info->count; + err = info.type; + *countp = info.count; } - kfree(info); return err; } @@ -301,14 +291,11 @@ static int copy_ctl_value_to_user(void __user *userdata, static int ctl_elem_read_user(struct snd_card *card, void __user *userdata, void __user *valuep) { - struct snd_ctl_elem_value *data; + struct snd_ctl_elem_value data; int err, type, count; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - err = copy_ctl_value_from_user(card, data, userdata, valuep, + memset(&data, 0, sizeof(data)); + err = copy_ctl_value_from_user(card, &data, userdata, valuep, &type, &count); if (err < 0) goto error; @@ -316,27 +303,23 @@ static int ctl_elem_read_user(struct snd_card *card, err = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; - err = snd_ctl_elem_read(card, data); + err = snd_ctl_elem_read(card, &data); if (err < 0) goto error; - err = copy_ctl_value_to_user(userdata, valuep, data, type, count); + err = copy_ctl_value_to_user(userdata, valuep, &data, type, count); error: - kfree(data); return err; } static int ctl_elem_write_user(struct snd_ctl_file *file, void __user *userdata, void __user *valuep) { - struct snd_ctl_elem_value *data; + struct snd_ctl_elem_value data; struct snd_card *card = file->card; int err, type, count; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (data == NULL) - return -ENOMEM; - - err = copy_ctl_value_from_user(card, data, userdata, valuep, + memset(&data, 0, sizeof(data)); + err = copy_ctl_value_from_user(card, &data, userdata, valuep, &type, &count); if (err < 0) goto error; @@ -344,12 +327,11 @@ static int ctl_elem_write_user(struct snd_ctl_file *file, err = snd_power_wait(card, SNDRV_CTL_POWER_D0); if (err < 0) goto error; - err = snd_ctl_elem_write(card, file, data); + err = snd_ctl_elem_write(card, file, &data); if (err < 0) goto error; - err = copy_ctl_value_to_user(userdata, valuep, data, type, count); + err = copy_ctl_value_to_user(userdata, valuep, &data, type, count); error: - kfree(data); return err; } @@ -384,48 +366,44 @@ static int snd_ctl_elem_add_compat(struct snd_ctl_file *file, struct snd_ctl_elem_info32 __user *data32, int replace) { - struct snd_ctl_elem_info *data; + struct snd_ctl_elem_info data; int err; - data = kzalloc(sizeof(*data), GFP_KERNEL); - if (! data) - return -ENOMEM; - + memset(&data, 0, sizeof(data)); err = -EFAULT; /* id, type, access, count */ \ - if (copy_from_user(&data->id, &data32->id, sizeof(data->id)) || - copy_from_user(&data->type, &data32->type, 3 * sizeof(u32))) + if (copy_from_user(&data.id, &data32->id, sizeof(data.id)) || + copy_from_user(&data.type, &data32->type, 3 * sizeof(u32))) goto error; - if (get_user(data->owner, &data32->owner)) + if (get_user(data.owner, &data32->owner)) goto error; - switch (data->type) { + switch (data.type) { case SNDRV_CTL_ELEM_TYPE_BOOLEAN: case SNDRV_CTL_ELEM_TYPE_INTEGER: - if (get_user(data->value.integer.min, &data32->value.integer.min) || - get_user(data->value.integer.max, &data32->value.integer.max) || - get_user(data->value.integer.step, &data32->value.integer.step)) + if (get_user(data.value.integer.min, &data32->value.integer.min) || + get_user(data.value.integer.max, &data32->value.integer.max) || + get_user(data.value.integer.step, &data32->value.integer.step)) goto error; break; case SNDRV_CTL_ELEM_TYPE_INTEGER64: - if (copy_from_user(&data->value.integer64, + if (copy_from_user(&data.value.integer64, &data32->value.integer64, - sizeof(data->value.integer64))) + sizeof(data.value.integer64))) goto error; break; case SNDRV_CTL_ELEM_TYPE_ENUMERATED: - if (copy_from_user(&data->value.enumerated, + if (copy_from_user(&data.value.enumerated, &data32->value.enumerated, - sizeof(data->value.enumerated))) + sizeof(data.value.enumerated))) goto error; - data->value.enumerated.names_ptr = - (uintptr_t)compat_ptr(data->value.enumerated.names_ptr); + data.value.enumerated.names_ptr = + (uintptr_t)compat_ptr(data.value.enumerated.names_ptr); break; default: break; } - err = snd_ctl_elem_add(file, data, replace); + err = snd_ctl_elem_add(file, &data, replace); error: - kfree(data); return err; } diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c index d535b9fa2424..eade2039152c 100644 --- a/sound/soc/soc-pcm.c +++ b/sound/soc/soc-pcm.c @@ -46,6 +46,8 @@ static const struct snd_pcm_hardware no_host_hardware = { SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME, .formats = SNDRV_PCM_FMTBIT_S16_LE | + SNDRV_PCM_FMTBIT_S24_LE | + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S32_LE, .period_bytes_min = PAGE_SIZE >> 2, .period_bytes_max = PAGE_SIZE >> 1, diff --git a/techpack/audio/4.0/asoc/Android.mk b/techpack/audio/4.0/asoc/Android.mk deleted file mode 100644 index 9d866f997644..000000000000 --- a/techpack/audio/4.0/asoc/Android.mk +++ /dev/null @@ -1,97 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,msmnile),true) -TARGET := msmnile -ifeq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile_au msmnile_gvmq)) -AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m -else -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif -endif - -ifeq ($(call is-board-platform,$(MSMSTEPPE)),true) -TARGET := talos -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,$(TRINKET)),true) -TARGET := trinket -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,kona),true) -TARGET := kona -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform,lito),true) -TARGET := lito -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -ifeq ($(call is-board-platform,atoll),true) -TARGET := atoll -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito atoll),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=platform_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_platform.ko -LOCAL_MODULE_KBUILD_NAME := platform_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list, ),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_cpe_lsm.ko -LOCAL_MODULE_KBUILD_NAME := cpe_lsm_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_machine_$(TARGET).ko -LOCAL_MODULE_KBUILD_NAME := machine_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/asoc/codecs/Android.mk b/techpack/audio/4.0/asoc/codecs/Android.mk deleted file mode 100644 index 593510245f69..000000000000 --- a/techpack/audio/4.0/asoc/codecs/Android.mk +++ /dev/null @@ -1,145 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,msmnile),true) -ifeq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile_au)) -AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m -else -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif -endif - -ifeq ($(call is-board-platform,$(MSMSTEPPE)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,$(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,kona),true) -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform,lito),true) -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -ifeq ($(call is-board-platform,atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito atoll),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=wcd_core_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -ifneq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile_au msmnile_gvmq)) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd_core.ko -LOCAL_MODULE_KBUILD_NAME := wcd_core_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd9xxx.ko -LOCAL_MODULE_KBUILD_NAME := wcd9xxx_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list, ),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd_cpe.ko -LOCAL_MODULE_KBUILD_NAME := wcd_cpe_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET)),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd_spi.ko -LOCAL_MODULE_KBUILD_NAME := wcd_spi_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -ifeq ($(call is-board-platform-in-list, ),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd9335.ko -LOCAL_MODULE_KBUILD_NAME := wcd9335_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa881x.ko -LOCAL_MODULE_KBUILD_NAME := wsa881x_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_mbhc.ko -LOCAL_MODULE_KBUILD_NAME := mbhc_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -############################################################ -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_stub.ko -LOCAL_MODULE_KBUILD_NAME := stub_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################## -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_hdmi.ko -LOCAL_MODULE_KBUILD_NAME := hdmi_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/asoc/codecs/bolero/Android.mk b/techpack/audio/4.0/asoc/codecs/bolero/Android.mk deleted file mode 100644 index 47791b4eb1be..000000000000 --- a/techpack/audio/4.0/asoc/codecs/bolero/Android.mk +++ /dev/null @@ -1,94 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,$(MSMSTEPPE) $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,kona),true) -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform,lito),true) -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -ifeq ($(call is-board-platform,atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona lito atoll),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=bolero_cdc_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_bolero_cdc.ko -LOCAL_MODULE_KBUILD_NAME := bolero_cdc_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa_macro.ko -LOCAL_MODULE_KBUILD_NAME := wsa_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_va_macro.ko -LOCAL_MODULE_KBUILD_NAME := va_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_tx_macro.ko -LOCAL_MODULE_KBUILD_NAME := tx_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_rx_macro.ko -LOCAL_MODULE_KBUILD_NAME := rx_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/asoc/codecs/wcd937x/Android.mk b/techpack/audio/4.0/asoc/codecs/wcd937x/Android.mk deleted file mode 100644 index 183c78dfe2d7..000000000000 --- a/techpack/audio/4.0/asoc/codecs/wcd937x/Android.mk +++ /dev/null @@ -1,61 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,$(MSMSTEPPE) $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) atoll),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=wcd937x_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd937x.ko -LOCAL_MODULE_KBUILD_NAME := wcd937x_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd937x_slave.ko -LOCAL_MODULE_KBUILD_NAME := wcd937x_slave_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/asoc/codecs/wcd938x/Android.mk b/techpack/audio/4.0/asoc/codecs/wcd938x/Android.mk deleted file mode 100644 index 87f16620ed13..000000000000 --- a/techpack/audio/4.0/asoc/codecs/wcd938x/Android.mk +++ /dev/null @@ -1,69 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,kona),true) -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform,lito),true) -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -ifeq ($(call is-board-platform,atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -ifeq ($(call is-board-platform,$(MSMSTEPPE)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,kona lito atoll $(MSMSTEPPE)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=wcd938x_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd938x.ko -LOCAL_MODULE_KBUILD_NAME := wcd938x_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd938x_slave.ko -LOCAL_MODULE_KBUILD_NAME := wcd938x_slave_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/dsp/Android.mk b/techpack/audio/4.0/dsp/Android.mk deleted file mode 100644 index 172fbee3f895..000000000000 --- a/techpack/audio/4.0/dsp/Android.mk +++ /dev/null @@ -1,104 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,msmnile),true) -ifeq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile_au msmnile_gvmq)) -AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m -else -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif -endif - -ifeq ($(call is-board-platform,$(MSMSTEPPE) $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform, kona),true) -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform, lito),true) -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -ifeq ($(call is-board-platform, atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) atoll kona lito),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=q6_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_q6.ko -LOCAL_MODULE_KBUILD_NAME := q6_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_adsp_loader.ko -LOCAL_MODULE_KBUILD_NAME := adsp_loader_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_q6_notifier.ko -LOCAL_MODULE_KBUILD_NAME := q6_notifier_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -############################################################ -ifneq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile_au msmnile_gvmq)) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_usf.ko -LOCAL_MODULE_KBUILD_NAME := usf_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################## -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_q6_pdr.ko -LOCAL_MODULE_KBUILD_NAME := q6_pdr_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/dsp/codecs/Android.mk b/techpack/audio/4.0/dsp/codecs/Android.mk deleted file mode 100644 index 48e3b8568f6e..000000000000 --- a/techpack/audio/4.0/dsp/codecs/Android.mk +++ /dev/null @@ -1,66 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform,$(MSMSTEPPE) $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,kona),true) -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform,lito),true) -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -ifeq ($(call is-board-platform,atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) atoll kona lito),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=native_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_native.ko -LOCAL_MODULE_KBUILD_NAME := native_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/include/uapi/Android.mk b/techpack/audio/4.0/include/uapi/Android.mk deleted file mode 100644 index f19a6c20337e..000000000000 --- a/techpack/audio/4.0/include/uapi/Android.mk +++ /dev/null @@ -1,30 +0,0 @@ -# Use this by setting -# LOCAL_HEADER_LIBRARIES := audio_kernel_headers - -LOCAL_PATH := $(call my-dir) -MYLOCAL_PATH := $(LOCAL_PATH) - -UAPI_OUT := $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/include - -AUDIO_KERNEL_HEADERS := $(call all-named-files-under,*.h,linux) $(call all-named-files-under,*.h,sound) - -HEADER_INSTALL_DIR := kernel/msm-$(TARGET_KERNEL_VERSION)/scripts - -BUILD_ROOT_RELATIVE := ../../../../../../../ - -include $(CLEAR_VARS) -LOCAL_MODULE := audio_kernel_headers -LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_PREBUILT_INT_KERNEL) -LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr - -GEN := $(addprefix $(UAPI_OUT)/,$(AUDIO_KERNEL_HEADERS)) -$(GEN): $(KERNEL_USR) -$(GEN): PRIVATE_PATH := $(MYLOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = $(shell cd $(PRODUCT_OUT)/obj/KERNEL_OBJ; $(BUILD_ROOT_RELATIVE)$(HEADER_INSTALL_DIR)/headers_install.sh $(BUILD_ROOT_RELATIVE)$(dir $@) $(BUILD_ROOT_RELATIVE)$(subst $(UAPI_OUT),$(MYLOCAL_PATH),$(dir $@)) $(notdir $@)) -$(GEN): $(addprefix $(MYLOCAL_PATH)/,$(AUDIO_KERNEL_HEADERS)) - $(transform-generated-source) - -LOCAL_GENERATED_SOURCES := $(GEN) -LOCAL_EXPORT_C_INCLUDE_DIRS := $(UAPI_OUT) - -include $(BUILD_HEADER_LIBRARY) diff --git a/techpack/audio/4.0/ipc/Android.mk b/techpack/audio/4.0/ipc/Android.mk deleted file mode 100644 index 25b98dd09d9b..000000000000 --- a/techpack/audio/4.0/ipc/Android.mk +++ /dev/null @@ -1,81 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,msmnile),true) -ifeq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile_au msmnile_gvmq)) -AUDIO_SELECT := CONFIG_SND_SOC_SA8155=m -else -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif -endif - -ifeq ($(call is-board-platform,$(MSMSTEPPE) $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,kona),true) -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform,atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -ifeq ($(call is-board-platform,lito),true) -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) atoll kona lito),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=apr_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_apr.ko -LOCAL_MODULE_KBUILD_NAME := apr_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET)),true) -ifneq ($(TARGET_PRODUCT), $(filter $(TARGET_PRODUCT), msmnile_au msmnile_gvmq)) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wglink.ko -LOCAL_MODULE_KBUILD_NAME := wglink_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -endif -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/4.0/soc/Android.mk b/techpack/audio/4.0/soc/Android.mk deleted file mode 100644 index 83101fceaded..000000000000 --- a/techpack/audio/4.0/soc/Android.mk +++ /dev/null @@ -1,103 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform,$(MSMSTEPPE) $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,kona),true) -AUDIO_SELECT := CONFIG_SND_SOC_KONA=m -endif - -ifeq ($(call is-board-platform,lito),true) -AUDIO_SELECT := CONFIG_SND_SOC_LITO=m -endif - -ifeq ($(call is-board-platform,atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_ATOLL=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile $(MSMSTEPPE) $(TRINKET) kona lito atoll),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=soc_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) atoll kona lito),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_pinctrl_lpi.ko -LOCAL_MODULE_KBUILD_NAME := pinctrl_lpi_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) kona), true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_pinctrl_wcd.ko -LOCAL_MODULE_KBUILD_NAME := pinctrl_wcd_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_swr.ko -LOCAL_MODULE_KBUILD_NAME := swr_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_swr_ctrl.ko -LOCAL_MODULE_KBUILD_NAME := swr_ctrl_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list, $(MSMSTEPPE) kona lito atoll),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_snd_event.ko -LOCAL_MODULE_KBUILD_NAME := snd_event_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/Android.mk b/techpack/audio/Android.mk deleted file mode 100644 index 468a7b309c64..000000000000 --- a/techpack/audio/Android.mk +++ /dev/null @@ -1,79 +0,0 @@ -# Android makefile for audio kernel modules -MY_LOCAL_PATH := $(call my-dir) - -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile $(MSMSTEPPE) $(TRINKET)),true) -UAPI_OUT := $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/include - -$(shell mkdir -p $(UAPI_OUT)/linux;) -$(shell mkdir -p $(UAPI_OUT)/sound;) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/codecs/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd934x/Module.symvers) - -include $(MY_LOCAL_PATH)/include/uapi/Android.mk -include $(MY_LOCAL_PATH)/ipc/Android.mk -include $(MY_LOCAL_PATH)/dsp/Android.mk -include $(MY_LOCAL_PATH)/dsp/codecs/Android.mk -include $(MY_LOCAL_PATH)/soc/Android.mk -include $(MY_LOCAL_PATH)/asoc/Android.mk -include $(MY_LOCAL_PATH)/asoc/codecs/Android.mk -include $(MY_LOCAL_PATH)/asoc/codecs/wcd934x/Android.mk -endif - -ifeq ($(call is-board-platform-in-list, atoll),true) -UAPI_OUT := $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/include - -$(shell mkdir -p $(UAPI_OUT)/linux;) -$(shell mkdir -p $(UAPI_OUT)/sound;) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/ipc/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/dsp/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/dsp/codecs/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/soc/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/asoc/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/asoc/codecs/Module.symvers) - -include $(MY_LOCAL_PATH)/4.0/include/uapi/Android.mk -include $(MY_LOCAL_PATH)/4.0/ipc/Android.mk -include $(MY_LOCAL_PATH)/4.0/dsp/Android.mk -include $(MY_LOCAL_PATH)/4.0/dsp/codecs/Android.mk -include $(MY_LOCAL_PATH)/4.0/soc/Android.mk -include $(MY_LOCAL_PATH)/4.0/asoc/Android.mk -include $(MY_LOCAL_PATH)/4.0/asoc/codecs/Android.mk -endif - -ifeq ($(call is-board-platform-in-list,sdm670 msmnile),true) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/aqt1000/Module.symvers) -include $(MY_LOCAL_PATH)/asoc/codecs/aqt1000/Android.mk -endif - -ifeq ($(call is-board-platform-in-list, $(MSMSTEPPE) $(TRINKET)),true) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/bolero/Module.symvers) -include $(MY_LOCAL_PATH)/asoc/codecs/bolero/Android.mk -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd937x/Module.symvers) -include $(MY_LOCAL_PATH)/asoc/codecs/wcd937x/Android.mk -endif - -ifeq ($(call is-board-platform-in-list, atoll),true) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/asoc/codecs/bolero/Module.symvers) -include $(MY_LOCAL_PATH)/4.0/asoc/codecs/bolero/Android.mk -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/asoc/codecs/wcd937x/Module.symvers) -include $(MY_LOCAL_PATH)/4.0/asoc/codecs/wcd937x/Android.mk -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/4.0/asoc/codecs/wcd938x/Module.symvers) -include $(MY_LOCAL_PATH)/4.0/asoc/codecs/wcd938x/Android.mk -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/sdm660_cdc/Module.symvers) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/msm_sdw/Module.symvers) -include $(MY_LOCAL_PATH)/asoc/codecs/sdm660_cdc/Android.mk -include $(MY_LOCAL_PATH)/asoc/codecs/msm_sdw/Android.mk -endif - -ifeq ($(call is-board-platform-in-list,msmnile),true) -$(shell rm -rf $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/wcd9360/Module.symvers) -include $(MY_LOCAL_PATH)/asoc/codecs/wcd9360/Android.mk -endif diff --git a/techpack/audio/asoc/Android.mk b/techpack/audio/asoc/Android.mk deleted file mode 100644 index d0e24e47bb53..000000000000 --- a/techpack/audio/asoc/Android.mk +++ /dev/null @@ -1,88 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,sdm845),true) -TARGET := sdm845 -AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -TARGET := sdm670 -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m -endif - -ifeq ($(call is-board-platform,msmnile),true) -TARGET := msmnile -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll),true) -TARGET := talos -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,$(TRINKET)),true) -TARGET := trinket -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile $(MSMSTEPPE) $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=platform_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_platform.ko -LOCAL_MODULE_KBUILD_NAME := platform_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605 $(TRINKET)),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_cpe_lsm.ko -LOCAL_MODULE_KBUILD_NAME := cpe_lsm_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_machine_$(TARGET).ko -LOCAL_MODULE_KBUILD_NAME := machine_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/Kbuild b/techpack/audio/asoc/Kbuild index 17e329eb7ca9..89f0b3369b40 100644 --- a/techpack/audio/asoc/Kbuild +++ b/techpack/audio/asoc/Kbuild @@ -177,6 +177,7 @@ CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \ -Werror\ -D__linux__ +CDEFINES += -DCONFIG_SND_SOC_CS35L41_FOR_CEPH KBUILD_CPPFLAGS += $(CDEFINES) # Currently, for versions of gcc which support it, the kernel Makefile @@ -232,6 +233,3 @@ machine_dlkm-y := $(MACHINE_OBJS) obj-$(CONFIG_SND_SOC_CPE) += cpe_lsm_dlkm.o cpe_lsm_dlkm-y := $(CPE_LSM_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/Android.mk b/techpack/audio/asoc/codecs/Android.mk deleted file mode 100644 index 0880f352ff4e..000000000000 --- a/techpack/audio/asoc/codecs/Android.mk +++ /dev/null @@ -1,133 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,sdm845),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m -endif - -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform,$(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile atoll $(MSMSTEPPE) $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=wcd_core_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd_core.ko -LOCAL_MODULE_KBUILD_NAME := wcd_core_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd9xxx.ko -LOCAL_MODULE_KBUILD_NAME := wcd9xxx_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list,sdm670 qcs605 $(TRINKET)),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd_cpe.ko -LOCAL_MODULE_KBUILD_NAME := wcd_cpe_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd_spi.ko -LOCAL_MODULE_KBUILD_NAME := wcd_spi_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605 $(TRINKET)),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd9335.ko -LOCAL_MODULE_KBUILD_NAME := wcd9335_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa881x.ko -LOCAL_MODULE_KBUILD_NAME := wsa881x_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_stub.ko -LOCAL_MODULE_KBUILD_NAME := stub_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_mbhc.ko -LOCAL_MODULE_KBUILD_NAME := mbhc_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_hdmi.ko -LOCAL_MODULE_KBUILD_NAME := hdmi_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/Kbuild b/techpack/audio/asoc/codecs/Kbuild index a5c17faec904..baaaa4a3b3bb 100644 --- a/techpack/audio/asoc/codecs/Kbuild +++ b/techpack/audio/asoc/codecs/Kbuild @@ -203,6 +203,8 @@ ifeq ($(KERNEL_BUILD), 1) obj-y += sdm660_cdc/ obj-y += msm_sdw/ obj-y += wcd9360/ + obj-y += tas2557/ + obj-y += cs35l41/ obj-y += wcd937x/ endif @@ -240,6 +242,3 @@ mbhc_dlkm-y := $(MBHC_OBJS) obj-$(CONFIG_SND_SOC_MSM_HDMI_CODEC_RX) += hdmi_dlkm.o hdmi_dlkm-y := $(HDMICODEC_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/aqt1000/Android.mk b/techpack/audio/asoc/codecs/aqt1000/Android.mk deleted file mode 100644 index ac26f6d52469..000000000000 --- a/techpack/audio/asoc/codecs/aqt1000/Android.mk +++ /dev/null @@ -1,41 +0,0 @@ -# Android makefile for audio kernel modules - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,sdm670),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=aqt1000_cdc_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_aqt1000_cdc.ko -LOCAL_MODULE_KBUILD_NAME := aqt1000_cdc_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/aqt1000/Kbuild b/techpack/audio/asoc/codecs/aqt1000/Kbuild index 5b05798b2688..518c90278fb8 100644 --- a/techpack/audio/asoc/codecs/aqt1000/Kbuild +++ b/techpack/audio/asoc/codecs/aqt1000/Kbuild @@ -119,6 +119,3 @@ endif # Module information used by KBuild framework obj-$(CONFIG_SND_SOC_AQT1000) += aqt1000_cdc_dlkm.o aqt1000_cdc_dlkm-y := $(AQT1000_CDC_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/bolero/Android.mk b/techpack/audio/asoc/codecs/bolero/Android.mk deleted file mode 100644 index ab7224434aa4..000000000000 --- a/techpack/audio/asoc/codecs/bolero/Android.mk +++ /dev/null @@ -1,82 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=bolero_cdc_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_bolero_cdc.ko -LOCAL_MODULE_KBUILD_NAME := bolero_cdc_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wsa_macro.ko -LOCAL_MODULE_KBUILD_NAME := wsa_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_va_macro.ko -LOCAL_MODULE_KBUILD_NAME := va_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_tx_macro.ko -LOCAL_MODULE_KBUILD_NAME := tx_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_rx_macro.ko -LOCAL_MODULE_KBUILD_NAME := rx_macro_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/bolero/Kbuild b/techpack/audio/asoc/codecs/bolero/Kbuild index 16766416244b..59b844b61392 100644 --- a/techpack/audio/asoc/codecs/bolero/Kbuild +++ b/techpack/audio/asoc/codecs/bolero/Kbuild @@ -143,6 +143,3 @@ tx_macro_dlkm-y := $(TX_OBJS) obj-$(CONFIG_RX_MACRO) += rx_macro_dlkm.o rx_macro_dlkm-y := $(RX_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/cs35l41/Kbuild b/techpack/audio/asoc/codecs/cs35l41/Kbuild new file mode 100644 index 000000000000..e7af92f568a1 --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/Kbuild @@ -0,0 +1,114 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + + + +ifeq ($(KERNEL_BUILD), 1) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.14 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM8150), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + + ifeq ($(CONFIG_ARCH_SDMSHRIKE), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG := y + +# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QTI internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ CS35L41 ############ + +# for CS35L41 Codec +ifdef CONFIG_SND_SOC_CS35L41 + CS35L41_OBJS += cs35l41.o + CS35L41_OBJS += cs35l41-i2c.o + CS35L41_OBJS += cs35l41-tables.o + CS35L41_OBJS += wm_adsp.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +EXTRA_CFLAGS += $(INCS) + + +CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +EXTRA_CFLAGS += -Wheader-guard +endif + +ifeq ($(KERNEL_BUILD), 0) +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers +endif + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_CS35L41) += cs35l41_dlkm.o +cs35l41_dlkm-y := $(CS35L41_OBJS) diff --git a/techpack/audio/asoc/codecs/cs35l41/Kconfig b/techpack/audio/asoc/codecs/cs35l41/Kconfig new file mode 100644 index 000000000000..111d2a1ab555 --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/Kconfig @@ -0,0 +1,1066 @@ +# Helper to resolve issues with configs that have SPI enabled but I2C +# modular, meaning we can't build the codec driver in with I2C support. +# We use an ordered list of conditional defaults to pick the appropriate +# setting - SPI can't be modular so that case doesn't need to be covered. +config SND_SOC_I2C_AND_SPI + tristate + default m if I2C=m + default y if I2C=y + default y if SPI_MASTER=y + +menu "CODEC drivers" + +config SND_SOC_ALL_CODECS + tristate "Build all ASoC CODEC drivers" + depends on COMPILE_TEST + select SND_SOC_88PM860X if MFD_88PM860X + select SND_SOC_L3 + select SND_SOC_AB8500_CODEC if ABX500_CORE + select SND_SOC_AC97_CODEC + select SND_SOC_AD1836 if SPI_MASTER + select SND_SOC_AD193X_SPI if SPI_MASTER + select SND_SOC_AD193X_I2C if I2C + select SND_SOC_AD1980 if SND_SOC_AC97_BUS + select SND_SOC_AD73311 + select SND_SOC_ADAU1373 if I2C + select SND_SOC_ADAU1761_I2C if I2C + select SND_SOC_ADAU1761_SPI if SPI + select SND_SOC_ADAU1781_I2C if I2C + select SND_SOC_ADAU1781_SPI if SPI + select SND_SOC_ADAV801 if SPI_MASTER + select SND_SOC_ADAV803 if I2C + select SND_SOC_ADAU1977_SPI if SPI_MASTER + select SND_SOC_ADAU1977_I2C if I2C + select SND_SOC_ADAU1701 if I2C + select SND_SOC_ADS117X + select SND_SOC_AK4104 if SPI_MASTER + select SND_SOC_AK4535 if I2C + select SND_SOC_AK4554 + select SND_SOC_AK4613 if I2C + select SND_SOC_AK4641 if I2C + select SND_SOC_AK4642 if I2C + select SND_SOC_AK4671 if I2C + select SND_SOC_AK5386 + select SND_SOC_ALC5623 if I2C + select SND_SOC_ALC5632 if I2C + select SND_SOC_CQ0093VC if MFD_DAVINCI_VOICECODEC + select SND_SOC_CIRRUS_PSIA + select SND_SOC_CS35L32 if I2C + select SND_SOC_CS35L33 if I2C + select SND_SOC_CS35L34 if I2C + select SND_SOC_CS35L35 if I2C + select SND_SOC_CS35L36 if I2C + select SND_SOC_CS35L41_SPI if SPI_MASTER + select SND_SOC_CS35L41_I2C if I2C + select SND_SOC_CS42L42_I2C if I2C + select SND_SOC_CS42L51_I2C if I2C + select SND_SOC_CS42L52 if I2C && INPUT + select SND_SOC_CS42L56 if I2C && INPUT + select SND_SOC_CS42L73 if I2C + select SND_SOC_CS4265 if I2C + select SND_SOC_CS4270 if I2C + select SND_SOC_CS4271_I2C if I2C + select SND_SOC_CS4271_SPI if SPI_MASTER + select SND_SOC_CS42XX8_I2C if I2C + select SND_SOC_CS4349 if I2C + select SND_SOC_CS43130 if I2C + select SND_SOC_CS47L24 if MFD_CS47L24 + select SND_SOC_CS53L30 if I2C + select SND_SOC_CX20442 if TTY + select SND_SOC_DA7210 if SND_SOC_I2C_AND_SPI + select SND_SOC_DA7213 if I2C + select SND_SOC_DA7218 if I2C + select SND_SOC_DA7219 if I2C + select SND_SOC_DA732X if I2C + select SND_SOC_DA9055 if I2C + select SND_SOC_DMIC + select SND_SOC_BT_SCO + select SND_SOC_ES8328_SPI if SPI_MASTER + select SND_SOC_ES8328_I2C if I2C + select SND_SOC_GTM601 + select SND_SOC_HDAC_HDMI + select SND_SOC_ICS43432 + select SND_SOC_INNO_RK3036 + select SND_SOC_ISABELLE if I2C + select SND_SOC_JZ4740_CODEC + select SND_SOC_LM4857 if I2C + select SND_SOC_LM49453 if I2C + select SND_SOC_MAX98088 if I2C + select SND_SOC_MAX98090 if I2C + select SND_SOC_MAX98095 if I2C + select SND_SOC_MAX98357A if GPIOLIB + select SND_SOC_MAX9867 if I2C + select SND_SOC_MAX98925 if I2C + select SND_SOC_MAX98926 if I2C + select SND_SOC_MAX9850 if I2C + select SND_SOC_MAX9768 if I2C + select SND_SOC_MAX9877 if I2C + select SND_SOC_MC13783 if MFD_MC13XXX + select SND_SOC_ML26124 if I2C + select SND_SOC_NAU8825 if I2C + select SND_SOC_PCM1681 if I2C + select SND_SOC_PCM179X_I2C if I2C + select SND_SOC_PCM179X_SPI if SPI_MASTER + select SND_SOC_PCM3008 + select SND_SOC_PCM3168A_I2C if I2C + select SND_SOC_PCM3168A_SPI if SPI_MASTER + select SND_SOC_PCM512x_I2C if I2C + select SND_SOC_PCM512x_SPI if SPI_MASTER + select SND_SOC_RT286 if I2C + select SND_SOC_RT298 if I2C + select SND_SOC_RT5514 if I2C + select SND_SOC_RT5616 if I2C + select SND_SOC_RT5631 if I2C + select SND_SOC_RT5640 if I2C + select SND_SOC_RT5645 if I2C + select SND_SOC_RT5651 if I2C + select SND_SOC_RT5659 if I2C + select SND_SOC_RT5670 if I2C + select SND_SOC_RT5677 if I2C && SPI_MASTER + select SND_SOC_SGTL5000 if I2C + select SND_SOC_SI476X if MFD_SI476X_CORE + select SND_SOC_SIRF_AUDIO_CODEC + select SND_SOC_SN95031 if INTEL_SCU_IPC + select SND_SOC_SPDIF + select SND_SOC_SSM2518 if I2C + select SND_SOC_SSM2602_SPI if SPI_MASTER + select SND_SOC_SSM2602_I2C if I2C + select SND_SOC_SSM4567 if I2C + select SND_SOC_STA32X if I2C + select SND_SOC_STA350 if I2C + select SND_SOC_STA529 if I2C + select SND_SOC_STAC9766 if SND_SOC_AC97_BUS + select SND_SOC_STI_SAS + select SND_SOC_TAS2552 if I2C + select SND_SOC_TAS5086 if I2C + select SND_SOC_TAS571X if I2C + select SND_SOC_TFA9879 if I2C + select SND_SOC_TLV320AIC23_I2C if I2C + select SND_SOC_TLV320AIC23_SPI if SPI_MASTER + select SND_SOC_TLV320AIC26 if SPI_MASTER + select SND_SOC_TLV320AIC31XX if I2C + select SND_SOC_TLV320AIC32X4 if I2C + select SND_SOC_TLV320AIC3X if I2C + select SND_SOC_TPA6130A2 if I2C + select SND_SOC_TLV320DAC33 if I2C + select SND_SOC_TS3A227E if I2C + select SND_SOC_TWL4030 if TWL4030_CORE + select SND_SOC_TWL6040 if TWL6040_CORE + select SND_SOC_UDA134X + select SND_SOC_UDA1380 if I2C + select SND_SOC_WL1273 if MFD_WL1273_CORE + select SND_SOC_WM0010 if SPI_MASTER + select SND_SOC_WM1250_EV1 if I2C + select SND_SOC_WM2000 if I2C + select SND_SOC_WM2200 if I2C + select SND_SOC_WM5100 if I2C + select SND_SOC_WM5102 if MFD_WM5102 + select SND_SOC_WM5110 if MFD_WM5110 + select SND_SOC_WM8350 if MFD_WM8350 + select SND_SOC_WM8400 if MFD_WM8400 + select SND_SOC_WM8510 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8523 if I2C + select SND_SOC_WM8580 if I2C + select SND_SOC_WM8711 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8727 + select SND_SOC_WM8728 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8731 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8737 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8741 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8750 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8753 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8770 if SPI_MASTER + select SND_SOC_WM8776 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8782 + select SND_SOC_WM8804_I2C if I2C + select SND_SOC_WM8804_SPI if SPI_MASTER + select SND_SOC_WM8900 if I2C + select SND_SOC_WM8903 if I2C + select SND_SOC_WM8904 if I2C + select SND_SOC_WM8940 if I2C + select SND_SOC_WM8955 if I2C + select SND_SOC_WM8960 if I2C + select SND_SOC_WM8961 if I2C + select SND_SOC_WM8962 if I2C && INPUT + select SND_SOC_WM8971 if I2C + select SND_SOC_WM8974 if I2C + select SND_SOC_WM8978 if I2C + select SND_SOC_WM8983 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8985 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8988 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8990 if I2C + select SND_SOC_WM8991 if I2C + select SND_SOC_WM8993 if I2C + select SND_SOC_WM8994 if MFD_WM8994 + select SND_SOC_WM8995 if SND_SOC_I2C_AND_SPI + select SND_SOC_WM8996 if I2C + select SND_SOC_WM8997 if MFD_WM8997 + select SND_SOC_WM8998 if MFD_WM8998 + select SND_SOC_WM9081 if I2C + select SND_SOC_WM9090 if I2C + select SND_SOC_WM9705 if SND_SOC_AC97_BUS + select SND_SOC_WM9712 if SND_SOC_AC97_BUS + select SND_SOC_WM9713 if SND_SOC_AC97_BUS + help + Normally ASoC codec drivers are only built if a machine driver which + uses them is also built since they are only usable with a machine + driver. Selecting this option will allow these drivers to be built + without an explicit machine driver for test and development purposes. + + Support for the bus types used to access the codecs to be built must + be selected separately. + + If unsure select "N". + +config SND_SOC_88PM860X + tristate + +config SND_SOC_ARIZONA + tristate + default y if SND_SOC_CS47L24=y + default y if SND_SOC_WM5102=y + default y if SND_SOC_WM5110=y + default y if SND_SOC_WM8997=y + default y if SND_SOC_WM8998=y + default m if SND_SOC_CS47L24=m + default m if SND_SOC_WM5102=m + default m if SND_SOC_WM5110=m + default m if SND_SOC_WM8997=m + default m if SND_SOC_WM8998=m + +config SND_SOC_WM_HUBS + tristate + default y if SND_SOC_WM8993=y || SND_SOC_WM8994=y + default m if SND_SOC_WM8993=m || SND_SOC_WM8994=m + +config SND_SOC_WM_ADSP + tristate + select SND_SOC_COMPRESS + default y if SND_SOC_CS47L24=y + default y if SND_SOC_WM5102=y + default y if SND_SOC_WM5110=y + default y if SND_SOC_WM2200=y + default m if SND_SOC_CS47L24=m + default m if SND_SOC_WM5102=m + default m if SND_SOC_WM5110=m + default m if SND_SOC_WM2200=m + +config SND_SOC_AB8500_CODEC + tristate + +config SND_SOC_AC97_CODEC + tristate "Build generic ASoC AC97 CODEC driver" + select SND_AC97_CODEC + select SND_SOC_AC97_BUS + +config SND_SOC_AD1836 + tristate + +config SND_SOC_AD193X + tristate + +config SND_SOC_AD193X_SPI + tristate + select SND_SOC_AD193X + +config SND_SOC_AD193X_I2C + tristate + select SND_SOC_AD193X + +config SND_SOC_AD1980 + select REGMAP_AC97 + tristate + +config SND_SOC_AD73311 + tristate + +config SND_SOC_ADAU1373 + tristate + +config SND_SOC_ADAU1701 + tristate "Analog Devices ADAU1701 CODEC" + depends on I2C + select SND_SOC_SIGMADSP_I2C + +config SND_SOC_ADAU17X1 + tristate + select SND_SOC_SIGMADSP_REGMAP + +config SND_SOC_ADAU1761 + tristate + select SND_SOC_ADAU17X1 + +config SND_SOC_ADAU1761_I2C + tristate + select SND_SOC_ADAU1761 + select REGMAP_I2C + +config SND_SOC_ADAU1761_SPI + tristate + select SND_SOC_ADAU1761 + select REGMAP_SPI + +config SND_SOC_ADAU1781 + select SND_SOC_ADAU17X1 + tristate + +config SND_SOC_ADAU1781_I2C + tristate + select SND_SOC_ADAU1781 + select REGMAP_I2C + +config SND_SOC_ADAU1781_SPI + tristate + select SND_SOC_ADAU1781 + select REGMAP_SPI + +config SND_SOC_ADAU1977 + tristate + +config SND_SOC_ADAU1977_SPI + tristate + select SND_SOC_ADAU1977 + select REGMAP_SPI + +config SND_SOC_ADAU1977_I2C + tristate + select SND_SOC_ADAU1977 + select REGMAP_I2C + +config SND_SOC_ADAV80X + tristate + +config SND_SOC_ADAV801 + tristate + select SND_SOC_ADAV80X + +config SND_SOC_ADAV803 + tristate + select SND_SOC_ADAV80X + +config SND_SOC_ADS117X + tristate + +config SND_SOC_AK4104 + tristate "AKM AK4104 CODEC" + depends on SPI_MASTER + +config SND_SOC_AK4535 + tristate + +config SND_SOC_AK4554 + tristate "AKM AK4554 CODEC" + +config SND_SOC_AK4613 + tristate "AKM AK4613 CODEC" + depends on I2C + +config SND_SOC_AK4641 + tristate + +config SND_SOC_AK4642 + tristate "AKM AK4642 CODEC" + depends on I2C + +config SND_SOC_AK4671 + tristate + +config SND_SOC_AK5386 + tristate "AKM AK5638 CODEC" + +config SND_SOC_ALC5623 + tristate "Realtek ALC5623 CODEC" + depends on I2C + +config SND_SOC_ALC5632 + tristate + +config SND_SOC_CQ0093VC + tristate + +config SND_SOC_CIRRUS_PSIA + tristate "Cirrus Logic PSIA Stub" + +config SND_SOC_CS35L32 + tristate "Cirrus Logic CS35L32 CODEC" + depends on I2C + +config SND_SOC_CS35L33 + tristate "Cirrus Logic CS35L33 CODEC" + depends on I2C + +config SND_SOC_CS35L34 + tristate "Cirrus Logic CS35L34 CODEC" + depends on I2C + +config SND_SOC_CS35L35 + tristate "Cirrus Logic CS35L35 CODEC" + depends on I2C + +config SND_SOC_CS35L36 + tristate "Cirrus Logic CS35L36 CODEC" + depends on I2C + +config SND_SOC_CS35L41 + tristate + select SND_SOC_WM_ADSP + +config SND_SOC_CS35L41_SPI + tristate "Cirrus Logic CS35L41 CODEC (SPI)" + depends on SPI_MASTER + select SND_SOC_CS35L41 + select REGMAP_SPI + +config SND_SOC_CS35L41_I2C + tristate "Cirrus Logic CS35L41 CODEC (I2C)" + depends on I2C + select SND_SOC_CS35L41 + select REGMAP_I2C + +config SND_SOC_CS42L42 + tristate "Cirrus Logic CS42L42 CODEC" + depends on I2C + +config SND_SOC_CS42L51 + tristate + +config SND_SOC_CS42L51_I2C + tristate "Cirrus Logic CS42L51 CODEC (I2C)" + depends on I2C + select SND_SOC_CS42L51 + +config SND_SOC_CS42L51 + tristate + +config SND_SOC_CS42L52 + tristate "Cirrus Logic CS42L52 CODEC" + depends on I2C && INPUT + +config SND_SOC_CS42L56 + tristate "Cirrus Logic CS42L56 CODEC" + depends on I2C && INPUT + +config SND_SOC_CS42L73 + tristate "Cirrus Logic CS42L73 CODEC" + depends on I2C + +config SND_SOC_CS4265 + tristate "Cirrus Logic CS4265 CODEC" + depends on I2C + select REGMAP_I2C + +# Cirrus Logic CS4270 Codec +config SND_SOC_CS4270 + tristate "Cirrus Logic CS4270 CODEC" + depends on I2C + +# Cirrus Logic CS4270 Codec VD = 3.3V Errata +# Select if you are affected by the errata where the part will not function +# if MCLK divide-by-1.5 is selected and VD is set to 3.3V. The driver will +# not select any sample rates that require MCLK to be divided by 1.5. +config SND_SOC_CS4270_VD33_ERRATA + bool + depends on SND_SOC_CS4270 + +config SND_SOC_CS4271 + tristate + +config SND_SOC_CS4271_I2C + tristate "Cirrus Logic CS4271 CODEC (I2C)" + depends on I2C + select SND_SOC_CS4271 + select REGMAP_I2C + +config SND_SOC_CS4271_SPI + tristate "Cirrus Logic CS4271 CODEC (SPI)" + depends on SPI_MASTER + select SND_SOC_CS4271 + select REGMAP_SPI + +config SND_SOC_CS42XX8 + tristate + +config SND_SOC_CS42XX8_I2C + tristate "Cirrus Logic CS42448/CS42888 CODEC (I2C)" + depends on I2C + select SND_SOC_CS42XX8 + select REGMAP_I2C + +# Cirrus Logic CS4349 HiFi DAC +config SND_SOC_CS4349 + tristate "Cirrus Logic CS4349 CODEC" + depends on I2C + +# Cirrus Logic CS43130 HiFi DAC +config SND_SOC_CS43130 + tristate "Cirrus Logic CS43130 CODEC" + depends on I2C + +config SND_SOC_CS47L24 + tristate + +config SND_SOC_CS53L30 + tristate "Cirrus Logic CS53L30 CODEC" + depends on I2C + +config SND_SOC_CX20442 + tristate + depends on TTY + +config SND_SOC_JZ4740_CODEC + select REGMAP_MMIO + tristate + +config SND_SOC_L3 + tristate + +config SND_SOC_DA7210 + tristate + +config SND_SOC_DA7213 + tristate + +config SND_SOC_DA7218 + tristate + +config SND_SOC_DA7219 + tristate + +config SND_SOC_DA732X + tristate + +config SND_SOC_DA9055 + tristate + +config SND_SOC_BT_SCO + tristate + +config SND_SOC_DMIC + tristate + +config SND_SOC_ES8328 + tristate "Everest Semi ES8328 CODEC" + +config SND_SOC_ES8328_I2C + tristate + select SND_SOC_ES8328 + +config SND_SOC_ES8328_SPI + tristate + select SND_SOC_ES8328 + +config SND_SOC_GTM601 + tristate 'GTM601 UMTS modem audio codec' + +config SND_SOC_HDAC_HDMI + tristate + select SND_HDA_EXT_CORE + select SND_PCM_ELD + select HDMI + +config SND_SOC_ICS43432 + tristate + +config SND_SOC_INNO_RK3036 + tristate "Inno codec driver for RK3036 SoC" + select REGMAP_MMIO + +config SND_SOC_ISABELLE + tristate + +config SND_SOC_LM49453 + tristate + +config SND_SOC_MAX98088 + tristate + +config SND_SOC_MAX98090 + tristate + +config SND_SOC_MAX98095 + tristate + +config SND_SOC_MAX98357A + tristate + +config SND_SOC_MAX9867 + tristate + +config SND_SOC_MAX98925 + tristate + +config SND_SOC_MAX98926 + tristate + +config SND_SOC_MAX9850 + tristate + +config SND_SOC_PCM1681 + tristate "Texas Instruments PCM1681 CODEC" + depends on I2C + +config SND_SOC_PCM179X + tristate + +config SND_SOC_PCM179X_I2C + tristate "Texas Instruments PCM179X CODEC (I2C)" + depends on I2C + select SND_SOC_PCM179X + help + Enable support for Texas Instruments PCM179x CODEC. + Select this if your PCM179x is connected via an I2C bus. + +config SND_SOC_PCM179X_SPI + tristate "Texas Instruments PCM179X CODEC (SPI)" + depends on SPI_MASTER + select SND_SOC_PCM179X + help + Enable support for Texas Instruments PCM179x CODEC. + Select this if your PCM179x is connected via an SPI bus. + +config SND_SOC_PCM3008 + tristate + +config SND_SOC_PCM3168A + tristate + +config SND_SOC_PCM3168A_I2C + tristate "Texas Instruments PCM3168A CODEC - I2C" + depends on I2C + select SND_SOC_PCM3168A + select REGMAP_I2C + +config SND_SOC_PCM3168A_SPI + tristate "Texas Instruments PCM3168A CODEC - SPI" + depends on SPI_MASTER + select SND_SOC_PCM3168A + select REGMAP_SPI + +config SND_SOC_PCM512x + tristate + +config SND_SOC_PCM512x_I2C + tristate "Texas Instruments PCM512x CODECs - I2C" + depends on I2C + select SND_SOC_PCM512x + select REGMAP_I2C + +config SND_SOC_PCM512x_SPI + tristate "Texas Instruments PCM512x CODECs - SPI" + depends on SPI_MASTER + select SND_SOC_PCM512x + select REGMAP_SPI + +config SND_SOC_RL6231 + tristate + default y if SND_SOC_RT5514=y + default y if SND_SOC_RT5616=y + default y if SND_SOC_RT5640=y + default y if SND_SOC_RT5645=y + default y if SND_SOC_RT5651=y + default y if SND_SOC_RT5659=y + default y if SND_SOC_RT5670=y + default y if SND_SOC_RT5677=y + default m if SND_SOC_RT5514=m + default m if SND_SOC_RT5616=m + default m if SND_SOC_RT5640=m + default m if SND_SOC_RT5645=m + default m if SND_SOC_RT5651=m + default m if SND_SOC_RT5659=m + default m if SND_SOC_RT5670=m + default m if SND_SOC_RT5677=m + +config SND_SOC_RL6347A + tristate + default y if SND_SOC_RT286=y + default y if SND_SOC_RT298=y + default m if SND_SOC_RT286=m + default m if SND_SOC_RT298=m + +config SND_SOC_RT286 + tristate + depends on I2C + +config SND_SOC_RT298 + tristate + depends on I2C + +config SND_SOC_RT5514 + tristate + +config SND_SOC_RT5616 + tristate "Realtek RT5616 CODEC" + depends on I2C + +config SND_SOC_RT5631 + tristate "Realtek ALC5631/RT5631 CODEC" + depends on I2C + +config SND_SOC_RT5640 + tristate + +config SND_SOC_RT5645 + tristate + +config SND_SOC_RT5651 + tristate + +config SND_SOC_RT5659 + tristate + +config SND_SOC_RT5670 + tristate + +config SND_SOC_RT5677 + tristate + select REGMAP_I2C + select REGMAP_IRQ + +config SND_SOC_RT5677_SPI + tristate + default SND_SOC_RT5677 && SPI + +#Freescale sgtl5000 codec +config SND_SOC_SGTL5000 + tristate "Freescale SGTL5000 CODEC" + depends on I2C + +config SND_SOC_SI476X + tristate + +config SND_SOC_SIGMADSP + tristate + select CRC32 + +config SND_SOC_SIGMADSP_I2C + tristate + select SND_SOC_SIGMADSP + +config SND_SOC_SIGMADSP_REGMAP + tristate + select SND_SOC_SIGMADSP + +config SND_SOC_SIRF_AUDIO_CODEC + tristate "SiRF SoC internal audio codec" + select REGMAP_MMIO + +config SND_SOC_SN95031 + tristate + +config SND_SOC_SPDIF + tristate "S/PDIF CODEC" + +config SND_SOC_SSM2518 + tristate + +config SND_SOC_SSM2602 + tristate + +config SND_SOC_SSM2602_SPI + tristate "Analog Devices SSM2602 CODEC - SPI" + depends on SPI_MASTER + select SND_SOC_SSM2602 + select REGMAP_SPI + +config SND_SOC_SSM2602_I2C + tristate "Analog Devices SSM2602 CODEC - I2C" + depends on I2C + select SND_SOC_SSM2602 + select REGMAP_I2C + +config SND_SOC_SSM4567 + tristate "Analog Devices ssm4567 amplifier driver support" + depends on I2C + +config SND_SOC_STA32X + tristate "STA326, STA328 and STA329 speaker amplifier" + depends on I2C + select REGMAP_I2C + +config SND_SOC_STA350 + tristate "STA350 speaker amplifier" + depends on I2C + +config SND_SOC_STA529 + tristate + +config SND_SOC_STAC9766 + tristate + +config SND_SOC_STI_SAS + tristate "codec Audio support for STI SAS codec" + +config SND_SOC_TAS2552 + tristate "Texas Instruments TAS2552 Mono Audio amplifier" + depends on I2C + +config SND_SOC_TAS5086 + tristate "Texas Instruments TAS5086 speaker amplifier" + depends on I2C + +config SND_SOC_TAS571X + tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers" + depends on I2C + +config SND_SOC_TFA9879 + tristate "NXP Semiconductors TFA9879 amplifier" + depends on I2C + +config SND_SOC_TLV320AIC23 + tristate + +config SND_SOC_TLV320AIC23_I2C + tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C" + depends on I2C + select SND_SOC_TLV320AIC23 + +config SND_SOC_TLV320AIC23_SPI + tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI" + depends on SPI_MASTER + select SND_SOC_TLV320AIC23 + +config SND_SOC_TLV320AIC26 + tristate + depends on SPI + +config SND_SOC_TLV320AIC31XX + tristate "Texas Instruments TLV320AIC31xx CODECs" + depends on I2C + select REGMAP_I2C + +config SND_SOC_TLV320AIC32X4 + tristate + +config SND_SOC_TLV320AIC3X + tristate "Texas Instruments TLV320AIC3x CODECs" + depends on I2C + +config SND_SOC_TLV320DAC33 + tristate + +config SND_SOC_TS3A227E + tristate "TI Headset/Mic detect and keypress chip" + depends on I2C + +config SND_SOC_TWL4030 + select MFD_TWL4030_AUDIO + tristate + +config SND_SOC_TWL6040 + tristate + +config SND_SOC_UDA134X + tristate + +config SND_SOC_UDA1380 + tristate + +config SND_SOC_WL1273 + tristate + +config SND_SOC_WM0010 + tristate + +config SND_SOC_WM1250_EV1 + tristate + +config SND_SOC_WM2000 + tristate + +config SND_SOC_WM2200 + tristate + +config SND_SOC_WM5100 + tristate + +config SND_SOC_WM5102 + tristate + +config SND_SOC_WM5110 + tristate + +config SND_SOC_WM8350 + tristate + +config SND_SOC_WM8400 + tristate + +config SND_SOC_WM8510 + tristate "Wolfson Microelectronics WM8510 CODEC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8523 + tristate "Wolfson Microelectronics WM8523 DAC" + depends on I2C + +config SND_SOC_WM8580 + tristate "Wolfson Microelectronics WM8523 CODEC" + depends on I2C + +config SND_SOC_WM8711 + tristate "Wolfson Microelectronics WM8711 CODEC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8727 + tristate + +config SND_SOC_WM8728 + tristate "Wolfson Microelectronics WM8728 DAC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8731 + tristate "Wolfson Microelectronics WM8731 CODEC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8737 + tristate "Wolfson Microelectronics WM8737 ADC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8741 + tristate "Wolfson Microelectronics WM8737 DAC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8750 + tristate "Wolfson Microelectronics WM8750 CODEC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8753 + tristate "Wolfson Microelectronics WM8753 CODEC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8770 + tristate "Wolfson Microelectronics WM8770 CODEC" + depends on SPI_MASTER + +config SND_SOC_WM8776 + tristate "Wolfson Microelectronics WM8776 CODEC" + depends on SND_SOC_I2C_AND_SPI + +config SND_SOC_WM8782 + tristate + +config SND_SOC_WM8804 + tristate + +config SND_SOC_WM8804_I2C + tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver I2C" + depends on I2C + select SND_SOC_WM8804 + select REGMAP_I2C + +config SND_SOC_WM8804_SPI + tristate "Wolfson Microelectronics WM8804 S/PDIF transceiver SPI" + depends on SPI_MASTER + select SND_SOC_WM8804 + select REGMAP_SPI + +config SND_SOC_WM8900 + tristate + +config SND_SOC_WM8903 + tristate "Wolfson Microelectronics WM8903 CODEC" + depends on I2C + +config SND_SOC_WM8904 + tristate + +config SND_SOC_WM8940 + tristate + +config SND_SOC_WM8955 + tristate + +config SND_SOC_WM8960 + tristate + +config SND_SOC_WM8961 + tristate + +config SND_SOC_WM8962 + tristate "Wolfson Microelectronics WM8962 CODEC" + depends on I2C && INPUT + +config SND_SOC_WM8971 + tristate + +config SND_SOC_WM8974 + tristate "Wolfson Microelectronics WM8974 codec" + depends on I2C + +config SND_SOC_WM8978 + tristate "Wolfson Microelectronics WM8978 codec" + depends on I2C + +config SND_SOC_WM8983 + tristate + +config SND_SOC_WM8985 + tristate + +config SND_SOC_WM8988 + tristate + +config SND_SOC_WM8990 + tristate + +config SND_SOC_WM8991 + tristate + +config SND_SOC_WM8993 + tristate + +config SND_SOC_WM8994 + tristate + +config SND_SOC_WM8995 + tristate + +config SND_SOC_WM8996 + tristate + +config SND_SOC_WM8997 + tristate + +config SND_SOC_WM8998 + tristate + +config SND_SOC_WM9081 + tristate + +config SND_SOC_WM9090 + tristate + +config SND_SOC_WM9705 + tristate + +config SND_SOC_WM9712 + tristate + +config SND_SOC_WM9713 + tristate + select REGMAP_AC97 + +# Amp +config SND_SOC_LM4857 + tristate + +config SND_SOC_MAX9768 + tristate + +config SND_SOC_MAX9877 + tristate + +config SND_SOC_MC13783 + tristate + +config SND_SOC_ML26124 + tristate + +config SND_SOC_NAU8825 + tristate + +config SND_SOC_TPA6130A2 + tristate "Texas Instruments TPA6130A2 headphone amplifier" + depends on I2C + +endmenu diff --git a/techpack/audio/asoc/codecs/cs35l41/Makefile b/techpack/audio/asoc/codecs/cs35l41/Makefile new file mode 100644 index 000000000000..e7e3ce8cf43a --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/Makefile @@ -0,0 +1,433 @@ +snd-soc-88pm860x-objs := 88pm860x-codec.o +snd-soc-ab8500-codec-objs := ab8500-codec.o +snd-soc-ac97-objs := ac97.o +snd-soc-ad1836-objs := ad1836.o +snd-soc-ad193x-objs := ad193x.o +snd-soc-ad193x-spi-objs := ad193x-spi.o +snd-soc-ad193x-i2c-objs := ad193x-i2c.o +snd-soc-ad1980-objs := ad1980.o +snd-soc-ad73311-objs := ad73311.o +snd-soc-adau1373-objs := adau1373.o +snd-soc-adau1701-objs := adau1701.o +snd-soc-adau17x1-objs := adau17x1.o +snd-soc-adau1761-objs := adau1761.o +snd-soc-adau1761-i2c-objs := adau1761-i2c.o +snd-soc-adau1761-spi-objs := adau1761-spi.o +snd-soc-adau1781-objs := adau1781.o +snd-soc-adau1781-i2c-objs := adau1781-i2c.o +snd-soc-adau1781-spi-objs := adau1781-spi.o +snd-soc-adau1977-objs := adau1977.o +snd-soc-adau1977-spi-objs := adau1977-spi.o +snd-soc-adau1977-i2c-objs := adau1977-i2c.o +snd-soc-adav80x-objs := adav80x.o +snd-soc-adav801-objs := adav801.o +snd-soc-adav803-objs := adav803.o +snd-soc-ads117x-objs := ads117x.o +snd-soc-ak4104-objs := ak4104.o +snd-soc-ak4535-objs := ak4535.o +snd-soc-ak4554-objs := ak4554.o +snd-soc-ak4613-objs := ak4613.o +snd-soc-ak4641-objs := ak4641.o +snd-soc-ak4642-objs := ak4642.o +snd-soc-ak4671-objs := ak4671.o +snd-soc-ak5386-objs := ak5386.o +snd-soc-arizona-objs := arizona.o +snd-soc-cq93vc-objs := cq93vc.o +snd-soc-cirrus-psia-objs := cirrus-psia.o +snd-soc-cs35l32-objs := cs35l32.o +snd-soc-cs35l33-objs := cs35l33.o +snd-soc-cs35l34-objs := cs35l34.o +snd-soc-cs35l35-objs := cs35l35.o +snd-soc-cs35l36-objs := cs35l36.o cs35l36-tables.o +snd-soc-cs35l41-objs := cs35l41.o +snd-soc-cs35l41-spi-objs := cs35l41-spi.o cs35l41-tables.o +snd-soc-cs35l41-i2c-objs := cs35l41-i2c.o cs35l41-tables.o +snd-soc-cs42l42-objs := cs42l42.o +snd-soc-cs42l51-objs := cs42l51.o +snd-soc-cs42l51-i2c-objs := cs42l51-i2c.o +snd-soc-cs42l52-objs := cs42l52.o +snd-soc-cs42l56-objs := cs42l56.o +snd-soc-cs42l73-objs := cs42l73.o +snd-soc-cs4265-objs := cs4265.o +snd-soc-cs4270-objs := cs4270.o +snd-soc-cs4271-objs := cs4271.o +snd-soc-cs4271-i2c-objs := cs4271-i2c.o +snd-soc-cs4271-spi-objs := cs4271-spi.o +snd-soc-cs42xx8-objs := cs42xx8.o +snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o +snd-soc-cs4349-objs := cs4349.o +snd-soc-cs43130-objs := cs43130.o +snd-soc-cs47l24-objs := cs47l24.o +snd-soc-cs53l30-objs := cs53l30.o +snd-soc-cx20442-objs := cx20442.o +snd-soc-da7210-objs := da7210.o +snd-soc-da7213-objs := da7213.o +snd-soc-da7218-objs := da7218.o +snd-soc-da7219-objs := da7219.o da7219-aad.o +snd-soc-da732x-objs := da732x.o +snd-soc-da9055-objs := da9055.o +snd-soc-bt-sco-objs := bt-sco.o +snd-soc-dmic-objs := dmic.o +snd-soc-es8328-objs := es8328.o +snd-soc-es8328-i2c-objs := es8328-i2c.o +snd-soc-es8328-spi-objs := es8328-spi.o +snd-soc-gtm601-objs := gtm601.o +snd-soc-hdac-hdmi-objs := hdac_hdmi.o +snd-soc-ics43432-objs := ics43432.o +snd-soc-inno-rk3036-objs := inno_rk3036.o +snd-soc-isabelle-objs := isabelle.o +snd-soc-jz4740-codec-objs := jz4740.o +snd-soc-l3-objs := l3.o +snd-soc-lm4857-objs := lm4857.o +snd-soc-lm49453-objs := lm49453.o +snd-soc-max9768-objs := max9768.o +snd-soc-max98088-objs := max98088.o +snd-soc-max98090-objs := max98090.o +snd-soc-max98095-objs := max98095.o +snd-soc-max98357a-objs := max98357a.o +snd-soc-max9867-objs := max9867.o +snd-soc-max98925-objs := max98925.o +snd-soc-max98926-objs := max98926.o +snd-soc-max9850-objs := max9850.o +snd-soc-mc13783-objs := mc13783.o +snd-soc-ml26124-objs := ml26124.o +snd-soc-nau8825-objs := nau8825.o +snd-soc-pcm1681-objs := pcm1681.o +snd-soc-pcm179x-codec-objs := pcm179x.o +snd-soc-pcm179x-i2c-objs := pcm179x-i2c.o +snd-soc-pcm179x-spi-objs := pcm179x-spi.o +snd-soc-pcm3008-objs := pcm3008.o +snd-soc-pcm3168a-objs := pcm3168a.o +snd-soc-pcm3168a-i2c-objs := pcm3168a-i2c.o +snd-soc-pcm3168a-spi-objs := pcm3168a-spi.o +snd-soc-pcm512x-objs := pcm512x.o +snd-soc-pcm512x-i2c-objs := pcm512x-i2c.o +snd-soc-pcm512x-spi-objs := pcm512x-spi.o +snd-soc-rl6231-objs := rl6231.o +snd-soc-rl6347a-objs := rl6347a.o +snd-soc-rt286-objs := rt286.o +snd-soc-rt298-objs := rt298.o +snd-soc-rt5514-objs := rt5514.o +snd-soc-rt5616-objs := rt5616.o +snd-soc-rt5631-objs := rt5631.o +snd-soc-rt5640-objs := rt5640.o +snd-soc-rt5645-objs := rt5645.o +snd-soc-rt5651-objs := rt5651.o +snd-soc-rt5659-objs := rt5659.o +snd-soc-rt5670-objs := rt5670.o +snd-soc-rt5677-objs := rt5677.o +snd-soc-rt5677-spi-objs := rt5677-spi.o +snd-soc-sgtl5000-objs := sgtl5000.o +snd-soc-alc5623-objs := alc5623.o +snd-soc-alc5632-objs := alc5632.o +snd-soc-sigmadsp-objs := sigmadsp.o +snd-soc-sigmadsp-i2c-objs := sigmadsp-i2c.o +snd-soc-sigmadsp-regmap-objs := sigmadsp-regmap.o +snd-soc-si476x-objs := si476x.o +snd-soc-sirf-audio-codec-objs := sirf-audio-codec.o +snd-soc-sn95031-objs := sn95031.o +snd-soc-spdif-tx-objs := spdif_transmitter.o +snd-soc-spdif-rx-objs := spdif_receiver.o +snd-soc-ssm2518-objs := ssm2518.o +snd-soc-ssm2602-objs := ssm2602.o +snd-soc-ssm2602-spi-objs := ssm2602-spi.o +snd-soc-ssm2602-i2c-objs := ssm2602-i2c.o +snd-soc-ssm4567-objs := ssm4567.o +snd-soc-sta32x-objs := sta32x.o +snd-soc-sta350-objs := sta350.o +snd-soc-sta529-objs := sta529.o +snd-soc-stac9766-objs := stac9766.o +snd-soc-sti-sas-objs := sti-sas.o +snd-soc-tas5086-objs := tas5086.o +snd-soc-tas571x-objs := tas571x.o +snd-soc-tfa9879-objs := tfa9879.o +snd-soc-tlv320aic23-objs := tlv320aic23.o +snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o +snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o +snd-soc-tlv320aic26-objs := tlv320aic26.o +snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o +snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o +snd-soc-tlv320aic3x-objs := tlv320aic3x.o +snd-soc-tlv320dac33-objs := tlv320dac33.o +snd-soc-ts3a227e-objs := ts3a227e.o +snd-soc-twl4030-objs := twl4030.o +snd-soc-twl6040-objs := twl6040.o +snd-soc-uda134x-objs := uda134x.o +snd-soc-uda1380-objs := uda1380.o +snd-soc-wl1273-objs := wl1273.o +snd-soc-wm-adsp-objs := wm_adsp.o +snd-soc-wm0010-objs := wm0010.o +snd-soc-wm1250-ev1-objs := wm1250-ev1.o +snd-soc-wm2000-objs := wm2000.o +snd-soc-wm2200-objs := wm2200.o +snd-soc-wm5100-objs := wm5100.o wm5100-tables.o +snd-soc-wm5102-objs := wm5102.o +snd-soc-wm5110-objs := wm5110.o +snd-soc-wm8350-objs := wm8350.o +snd-soc-wm8400-objs := wm8400.o +snd-soc-wm8510-objs := wm8510.o +snd-soc-wm8523-objs := wm8523.o +snd-soc-wm8580-objs := wm8580.o +snd-soc-wm8711-objs := wm8711.o +snd-soc-wm8727-objs := wm8727.o +snd-soc-wm8728-objs := wm8728.o +snd-soc-wm8731-objs := wm8731.o +snd-soc-wm8737-objs := wm8737.o +snd-soc-wm8741-objs := wm8741.o +snd-soc-wm8750-objs := wm8750.o +snd-soc-wm8753-objs := wm8753.o +snd-soc-wm8770-objs := wm8770.o +snd-soc-wm8776-objs := wm8776.o +snd-soc-wm8782-objs := wm8782.o +snd-soc-wm8804-objs := wm8804.o +snd-soc-wm8804-i2c-objs := wm8804-i2c.o +snd-soc-wm8804-spi-objs := wm8804-spi.o +snd-soc-wm8900-objs := wm8900.o +snd-soc-wm8903-objs := wm8903.o +snd-soc-wm8904-objs := wm8904.o +snd-soc-wm8996-objs := wm8996.o +snd-soc-wm8940-objs := wm8940.o +snd-soc-wm8955-objs := wm8955.o +snd-soc-wm8960-objs := wm8960.o +snd-soc-wm8961-objs := wm8961.o +snd-soc-wm8962-objs := wm8962.o +snd-soc-wm8971-objs := wm8971.o +snd-soc-wm8974-objs := wm8974.o +snd-soc-wm8978-objs := wm8978.o +snd-soc-wm8983-objs := wm8983.o +snd-soc-wm8985-objs := wm8985.o +snd-soc-wm8988-objs := wm8988.o +snd-soc-wm8990-objs := wm8990.o +snd-soc-wm8991-objs := wm8991.o +snd-soc-wm8993-objs := wm8993.o +snd-soc-wm8994-objs := wm8994.o wm8958-dsp2.o +snd-soc-wm8995-objs := wm8995.o +snd-soc-wm8997-objs := wm8997.o +snd-soc-wm8998-objs := wm8998.o +snd-soc-wm9081-objs := wm9081.o +snd-soc-wm9090-objs := wm9090.o +snd-soc-wm9705-objs := wm9705.o +snd-soc-wm9712-objs := wm9712.o +snd-soc-wm9713-objs := wm9713.o +snd-soc-wm-hubs-objs := wm_hubs.o + +# Amp +snd-soc-max9877-objs := max9877.o +snd-soc-tpa6130a2-objs := tpa6130a2.o +snd-soc-tas2552-objs := tas2552.o + +obj-$(CONFIG_SND_SOC_88PM860X) += snd-soc-88pm860x.o +obj-$(CONFIG_SND_SOC_AB8500_CODEC) += snd-soc-ab8500-codec.o +obj-$(CONFIG_SND_SOC_AC97_CODEC) += snd-soc-ac97.o +obj-$(CONFIG_SND_SOC_AD1836) += snd-soc-ad1836.o +obj-$(CONFIG_SND_SOC_AD193X) += snd-soc-ad193x.o +obj-$(CONFIG_SND_SOC_AD193X_SPI) += snd-soc-ad193x-spi.o +obj-$(CONFIG_SND_SOC_AD193X_I2C) += snd-soc-ad193x-i2c.o +obj-$(CONFIG_SND_SOC_AD1980) += snd-soc-ad1980.o +obj-$(CONFIG_SND_SOC_AD73311) += snd-soc-ad73311.o +obj-$(CONFIG_SND_SOC_ADAU1373) += snd-soc-adau1373.o +obj-$(CONFIG_SND_SOC_ADAU1701) += snd-soc-adau1701.o +obj-$(CONFIG_SND_SOC_ADAU17X1) += snd-soc-adau17x1.o +obj-$(CONFIG_SND_SOC_ADAU1761) += snd-soc-adau1761.o +obj-$(CONFIG_SND_SOC_ADAU1761_I2C) += snd-soc-adau1761-i2c.o +obj-$(CONFIG_SND_SOC_ADAU1761_SPI) += snd-soc-adau1761-spi.o +obj-$(CONFIG_SND_SOC_ADAU1781) += snd-soc-adau1781.o +obj-$(CONFIG_SND_SOC_ADAU1781_I2C) += snd-soc-adau1781-i2c.o +obj-$(CONFIG_SND_SOC_ADAU1781_SPI) += snd-soc-adau1781-spi.o +obj-$(CONFIG_SND_SOC_ADAU1977) += snd-soc-adau1977.o +obj-$(CONFIG_SND_SOC_ADAU1977_SPI) += snd-soc-adau1977-spi.o +obj-$(CONFIG_SND_SOC_ADAU1977_I2C) += snd-soc-adau1977-i2c.o +obj-$(CONFIG_SND_SOC_ADAV80X) += snd-soc-adav80x.o +obj-$(CONFIG_SND_SOC_ADAV801) += snd-soc-adav801.o +obj-$(CONFIG_SND_SOC_ADAV803) += snd-soc-adav803.o +obj-$(CONFIG_SND_SOC_ADS117X) += snd-soc-ads117x.o +obj-$(CONFIG_SND_SOC_AK4104) += snd-soc-ak4104.o +obj-$(CONFIG_SND_SOC_AK4535) += snd-soc-ak4535.o +obj-$(CONFIG_SND_SOC_AK4554) += snd-soc-ak4554.o +obj-$(CONFIG_SND_SOC_AK4613) += snd-soc-ak4613.o +obj-$(CONFIG_SND_SOC_AK4641) += snd-soc-ak4641.o +obj-$(CONFIG_SND_SOC_AK4642) += snd-soc-ak4642.o +obj-$(CONFIG_SND_SOC_AK4671) += snd-soc-ak4671.o +obj-$(CONFIG_SND_SOC_AK5386) += snd-soc-ak5386.o +obj-$(CONFIG_SND_SOC_ALC5623) += snd-soc-alc5623.o +obj-$(CONFIG_SND_SOC_ALC5632) += snd-soc-alc5632.o +obj-$(CONFIG_SND_SOC_ARIZONA) += snd-soc-arizona.o +obj-$(CONFIG_SND_SOC_CQ0093VC) += snd-soc-cq93vc.o +obj-$(CONFIG_SND_SOC_CIRRUS_PSIA) += snd-soc-cirrus-psia.o +obj-$(CONFIG_SND_SOC_CS35L32) += snd-soc-cs35l32.o +obj-$(CONFIG_SND_SOC_CS35L33) += snd-soc-cs35l33.o +obj-$(CONFIG_SND_SOC_CS35L34) += snd-soc-cs35l34.o +obj-$(CONFIG_SND_SOC_CS35L35) += snd-soc-cs35l35.o +obj-$(CONFIG_SND_SOC_CS35L41) += snd-soc-cs35l41.o +obj-$(CONFIG_SND_SOC_CS35L41_SPI) += snd-soc-cs35l41-spi.o +obj-$(CONFIG_SND_SOC_CS35L41_I2C) += snd-soc-cs35l41-i2c.o +obj-$(CONFIG_SND_SOC_CS35L36) += snd-soc-cs35l36.o +obj-$(CONFIG_SND_SOC_CS42L42) += snd-soc-cs42l42.o +obj-$(CONFIG_SND_SOC_CS42L51) += snd-soc-cs42l51.o +obj-$(CONFIG_SND_SOC_CS42L51_I2C) += snd-soc-cs42l51-i2c.o +obj-$(CONFIG_SND_SOC_CS42L52) += snd-soc-cs42l52.o +obj-$(CONFIG_SND_SOC_CS42L56) += snd-soc-cs42l56.o +obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o +obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o +obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o +obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o +obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o +obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o +obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o +obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o +obj-$(CONFIG_SND_SOC_CS4349) += snd-soc-cs4349.o +obj-$(CONFIG_SND_SOC_CS43130) += snd-soc-cs43130.o +obj-$(CONFIG_SND_SOC_CS47L24) += snd-soc-cs47l24.o +obj-$(CONFIG_SND_SOC_CS53L30) += snd-soc-cs53l30.o +obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o +obj-$(CONFIG_SND_SOC_DA7210) += snd-soc-da7210.o +obj-$(CONFIG_SND_SOC_DA7213) += snd-soc-da7213.o +obj-$(CONFIG_SND_SOC_DA7218) += snd-soc-da7218.o +obj-$(CONFIG_SND_SOC_DA7219) += snd-soc-da7219.o +obj-$(CONFIG_SND_SOC_DA732X) += snd-soc-da732x.o +obj-$(CONFIG_SND_SOC_DA9055) += snd-soc-da9055.o +obj-$(CONFIG_SND_SOC_BT_SCO) += snd-soc-bt-sco.o +obj-$(CONFIG_SND_SOC_DMIC) += snd-soc-dmic.o +obj-$(CONFIG_SND_SOC_ES8328) += snd-soc-es8328.o +obj-$(CONFIG_SND_SOC_ES8328_I2C)+= snd-soc-es8328-i2c.o +obj-$(CONFIG_SND_SOC_ES8328_SPI)+= snd-soc-es8328-spi.o +obj-$(CONFIG_SND_SOC_GTM601) += snd-soc-gtm601.o +obj-$(CONFIG_SND_SOC_HDAC_HDMI) += snd-soc-hdac-hdmi.o +obj-$(CONFIG_SND_SOC_ICS43432) += snd-soc-ics43432.o +obj-$(CONFIG_SND_SOC_INNO_RK3036) += snd-soc-inno-rk3036.o +obj-$(CONFIG_SND_SOC_ISABELLE) += snd-soc-isabelle.o +obj-$(CONFIG_SND_SOC_JZ4740_CODEC) += snd-soc-jz4740-codec.o +obj-$(CONFIG_SND_SOC_L3) += snd-soc-l3.o +obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o +obj-$(CONFIG_SND_SOC_LM49453) += snd-soc-lm49453.o +obj-$(CONFIG_SND_SOC_MAX9768) += snd-soc-max9768.o +obj-$(CONFIG_SND_SOC_MAX98088) += snd-soc-max98088.o +obj-$(CONFIG_SND_SOC_MAX98090) += snd-soc-max98090.o +obj-$(CONFIG_SND_SOC_MAX98095) += snd-soc-max98095.o +obj-$(CONFIG_SND_SOC_MAX98357A) += snd-soc-max98357a.o +obj-$(CONFIG_SND_SOC_MAX9867) += snd-soc-max9867.o +obj-$(CONFIG_SND_SOC_MAX98925) += snd-soc-max98925.o +obj-$(CONFIG_SND_SOC_MAX98926) += snd-soc-max98926.o +obj-$(CONFIG_SND_SOC_MAX9850) += snd-soc-max9850.o +obj-$(CONFIG_SND_SOC_MC13783) += snd-soc-mc13783.o +obj-$(CONFIG_SND_SOC_ML26124) += snd-soc-ml26124.o +obj-$(CONFIG_SND_SOC_NAU8825) += snd-soc-nau8825.o +obj-$(CONFIG_SND_SOC_PCM1681) += snd-soc-pcm1681.o +obj-$(CONFIG_SND_SOC_PCM179X) += snd-soc-pcm179x-codec.o +obj-$(CONFIG_SND_SOC_PCM179X_I2C) += snd-soc-pcm179x-i2c.o +obj-$(CONFIG_SND_SOC_PCM179X_SPI) += snd-soc-pcm179x-spi.o +obj-$(CONFIG_SND_SOC_PCM3008) += snd-soc-pcm3008.o +obj-$(CONFIG_SND_SOC_PCM3168A) += snd-soc-pcm3168a.o +obj-$(CONFIG_SND_SOC_PCM3168A_I2C) += snd-soc-pcm3168a-i2c.o +obj-$(CONFIG_SND_SOC_PCM3168A_SPI) += snd-soc-pcm3168a-spi.o +obj-$(CONFIG_SND_SOC_PCM512x) += snd-soc-pcm512x.o +obj-$(CONFIG_SND_SOC_PCM512x_I2C) += snd-soc-pcm512x-i2c.o +obj-$(CONFIG_SND_SOC_PCM512x_SPI) += snd-soc-pcm512x-spi.o +obj-$(CONFIG_SND_SOC_RL6231) += snd-soc-rl6231.o +obj-$(CONFIG_SND_SOC_RL6347A) += snd-soc-rl6347a.o +obj-$(CONFIG_SND_SOC_RT286) += snd-soc-rt286.o +obj-$(CONFIG_SND_SOC_RT298) += snd-soc-rt298.o +obj-$(CONFIG_SND_SOC_RT5514) += snd-soc-rt5514.o +obj-$(CONFIG_SND_SOC_RT5616) += snd-soc-rt5616.o +obj-$(CONFIG_SND_SOC_RT5631) += snd-soc-rt5631.o +obj-$(CONFIG_SND_SOC_RT5640) += snd-soc-rt5640.o +obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o +obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o +obj-$(CONFIG_SND_SOC_RT5659) += snd-soc-rt5659.o +obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o +obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o +obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o +obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o +obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o +obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o +obj-$(CONFIG_SND_SOC_SIGMADSP_REGMAP) += snd-soc-sigmadsp-regmap.o +obj-$(CONFIG_SND_SOC_SI476X) += snd-soc-si476x.o +obj-$(CONFIG_SND_SOC_SN95031) +=snd-soc-sn95031.o +obj-$(CONFIG_SND_SOC_SPDIF) += snd-soc-spdif-rx.o snd-soc-spdif-tx.o +obj-$(CONFIG_SND_SOC_SSM2518) += snd-soc-ssm2518.o +obj-$(CONFIG_SND_SOC_SSM2602) += snd-soc-ssm2602.o +obj-$(CONFIG_SND_SOC_SSM2602_SPI) += snd-soc-ssm2602-spi.o +obj-$(CONFIG_SND_SOC_SSM2602_I2C) += snd-soc-ssm2602-i2c.o +obj-$(CONFIG_SND_SOC_SSM4567) += snd-soc-ssm4567.o +obj-$(CONFIG_SND_SOC_STA32X) += snd-soc-sta32x.o +obj-$(CONFIG_SND_SOC_STA350) += snd-soc-sta350.o +obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o +obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o +obj-$(CONFIG_SND_SOC_STI_SAS) += snd-soc-sti-sas.o +obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o +obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o +obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o +obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o +obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o +obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o +obj-$(CONFIG_SND_SOC_TLV320AIC26) += snd-soc-tlv320aic26.o +obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o +obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o +obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o +obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o +obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o +obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o +obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o +obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o +obj-$(CONFIG_SND_SOC_UDA1380) += snd-soc-uda1380.o +obj-$(CONFIG_SND_SOC_WL1273) += snd-soc-wl1273.o +obj-$(CONFIG_SND_SOC_WM0010) += snd-soc-wm0010.o +obj-$(CONFIG_SND_SOC_WM1250_EV1) += snd-soc-wm1250-ev1.o +obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o +obj-$(CONFIG_SND_SOC_WM2200) += snd-soc-wm2200.o +obj-$(CONFIG_SND_SOC_WM5100) += snd-soc-wm5100.o +obj-$(CONFIG_SND_SOC_WM5102) += snd-soc-wm5102.o +obj-$(CONFIG_SND_SOC_WM5110) += snd-soc-wm5110.o +obj-$(CONFIG_SND_SOC_WM8350) += snd-soc-wm8350.o +obj-$(CONFIG_SND_SOC_WM8400) += snd-soc-wm8400.o +obj-$(CONFIG_SND_SOC_WM8510) += snd-soc-wm8510.o +obj-$(CONFIG_SND_SOC_WM8523) += snd-soc-wm8523.o +obj-$(CONFIG_SND_SOC_WM8580) += snd-soc-wm8580.o +obj-$(CONFIG_SND_SOC_WM8711) += snd-soc-wm8711.o +obj-$(CONFIG_SND_SOC_WM8727) += snd-soc-wm8727.o +obj-$(CONFIG_SND_SOC_WM8728) += snd-soc-wm8728.o +obj-$(CONFIG_SND_SOC_WM8731) += snd-soc-wm8731.o +obj-$(CONFIG_SND_SOC_WM8737) += snd-soc-wm8737.o +obj-$(CONFIG_SND_SOC_WM8741) += snd-soc-wm8741.o +obj-$(CONFIG_SND_SOC_WM8750) += snd-soc-wm8750.o +obj-$(CONFIG_SND_SOC_WM8753) += snd-soc-wm8753.o +obj-$(CONFIG_SND_SOC_WM8770) += snd-soc-wm8770.o +obj-$(CONFIG_SND_SOC_WM8776) += snd-soc-wm8776.o +obj-$(CONFIG_SND_SOC_WM8782) += snd-soc-wm8782.o +obj-$(CONFIG_SND_SOC_WM8804) += snd-soc-wm8804.o +obj-$(CONFIG_SND_SOC_WM8804_I2C) += snd-soc-wm8804-i2c.o +obj-$(CONFIG_SND_SOC_WM8804_SPI) += snd-soc-wm8804-spi.o +obj-$(CONFIG_SND_SOC_WM8900) += snd-soc-wm8900.o +obj-$(CONFIG_SND_SOC_WM8903) += snd-soc-wm8903.o +obj-$(CONFIG_SND_SOC_WM8904) += snd-soc-wm8904.o +obj-$(CONFIG_SND_SOC_WM8996) += snd-soc-wm8996.o +obj-$(CONFIG_SND_SOC_WM8940) += snd-soc-wm8940.o +obj-$(CONFIG_SND_SOC_WM8955) += snd-soc-wm8955.o +obj-$(CONFIG_SND_SOC_WM8960) += snd-soc-wm8960.o +obj-$(CONFIG_SND_SOC_WM8961) += snd-soc-wm8961.o +obj-$(CONFIG_SND_SOC_WM8962) += snd-soc-wm8962.o +obj-$(CONFIG_SND_SOC_WM8971) += snd-soc-wm8971.o +obj-$(CONFIG_SND_SOC_WM8974) += snd-soc-wm8974.o +obj-$(CONFIG_SND_SOC_WM8978) += snd-soc-wm8978.o +obj-$(CONFIG_SND_SOC_WM8983) += snd-soc-wm8983.o +obj-$(CONFIG_SND_SOC_WM8985) += snd-soc-wm8985.o +obj-$(CONFIG_SND_SOC_WM8988) += snd-soc-wm8988.o +obj-$(CONFIG_SND_SOC_WM8990) += snd-soc-wm8990.o +obj-$(CONFIG_SND_SOC_WM8991) += snd-soc-wm8991.o +obj-$(CONFIG_SND_SOC_WM8993) += snd-soc-wm8993.o +obj-$(CONFIG_SND_SOC_WM8994) += snd-soc-wm8994.o +obj-$(CONFIG_SND_SOC_WM8995) += snd-soc-wm8995.o +obj-$(CONFIG_SND_SOC_WM8997) += snd-soc-wm8997.o +obj-$(CONFIG_SND_SOC_WM8998) += snd-soc-wm8998.o +obj-$(CONFIG_SND_SOC_WM9081) += snd-soc-wm9081.o +obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o +obj-$(CONFIG_SND_SOC_WM9705) += snd-soc-wm9705.o +obj-$(CONFIG_SND_SOC_WM9712) += snd-soc-wm9712.o +obj-$(CONFIG_SND_SOC_WM9713) += snd-soc-wm9713.o +obj-$(CONFIG_SND_SOC_WM_ADSP) += snd-soc-wm-adsp.o +obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o + +# Amp +obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o +obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o diff --git a/techpack/audio/asoc/codecs/cs35l41/cs35l41-i2c.c b/techpack/audio/asoc/codecs/cs35l41/cs35l41-i2c.c new file mode 100644 index 000000000000..e33bc7412feb --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/cs35l41-i2c.c @@ -0,0 +1,123 @@ +/* + * cs35l41-i2c.c -- CS35l41 I2C driver + * + * Copyright 2017 Cirrus Logic, Inc. + * + * Author: David Rhodes + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm_adsp.h" +#include "cs35l41.h" +#include + +static struct regmap_config cs35l41_regmap_i2c = { + .reg_bits = 32, + .val_bits = 32, + .reg_stride = 4, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .precious_reg = cs35l41_precious_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct i2c_device_id cs35l41_id_i2c[] = { + {"cs35l40", 0}, + {"cs35l41", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, cs35l41_id_i2c); + +static int cs35l41_i2c_probe(struct i2c_client *client, + const struct i2c_device_id *id) +{ + struct cs35l41_private *cs35l41; + struct device *dev = &client->dev; + struct cs35l41_platform_data *pdata = dev_get_platdata(dev); + const struct regmap_config *regmap_config = &cs35l41_regmap_i2c; + int ret; + + + dev_info(dev, "cs35l41 i2c probe start\n"); + + cs35l41 = devm_kzalloc(dev, sizeof(struct cs35l41_private), GFP_KERNEL); + + if (cs35l41 == NULL) + return -ENOMEM; + + cs35l41->dev = dev; + cs35l41->irq = client->irq; + cs35l41->bus_spi = false; + + i2c_set_clientdata(client, cs35l41); + cs35l41->regmap = devm_regmap_init_i2c(client, regmap_config); + if (IS_ERR(cs35l41->regmap)) { + ret = PTR_ERR(cs35l41->regmap); + dev_err(cs35l41->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + return cs35l41_probe(cs35l41, pdata); +} + +static int cs35l41_i2c_remove(struct i2c_client *client) +{ + struct cs35l41_private *cs35l41 = i2c_get_clientdata(client); + + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + wm_adsp2_remove(&cs35l41->dsp); + regulator_bulk_disable(cs35l41->num_supplies, cs35l41->supplies); + snd_soc_unregister_codec(cs35l41->dev); + return 0; +} + +static const struct of_device_id cs35l41_of_match[] = { + {.compatible = "cirrus,cs35l40"}, + {.compatible = "cirrus,cs35l41"}, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l41_of_match); + +static struct i2c_driver cs35l41_i2c_driver = { + .driver = { + .name = "cs35l41", + .of_match_table = cs35l41_of_match, + }, + .id_table = cs35l41_id_i2c, + .probe = cs35l41_i2c_probe, + .remove = cs35l41_i2c_remove, +}; + +module_i2c_driver(cs35l41_i2c_driver); + +MODULE_DESCRIPTION("I2C CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/techpack/audio/asoc/codecs/cs35l41/cs35l41-spi.c b/techpack/audio/asoc/codecs/cs35l41/cs35l41-spi.c new file mode 100644 index 000000000000..49ee3a8d2058 --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/cs35l41-spi.c @@ -0,0 +1,114 @@ +/* + * cs35l41-spi.c -- CS35l41 SPI driver + * + * Copyright 2017 Cirrus Logic, Inc. + * + * Author: David Rhodes + * + * 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. + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm_adsp.h" +#include "cs35l41.h" +#include + +static struct regmap_config cs35l41_regmap_spi = { + .reg_bits = 32, + .val_bits = 32, + .pad_bits = 16, + .reg_stride = 4, + .reg_format_endian = REGMAP_ENDIAN_BIG, + .val_format_endian = REGMAP_ENDIAN_BIG, + .max_register = CS35L41_LASTREG, + .reg_defaults = cs35l41_reg, + .num_reg_defaults = ARRAY_SIZE(cs35l41_reg), + .volatile_reg = cs35l41_volatile_reg, + .readable_reg = cs35l41_readable_reg, + .cache_type = REGCACHE_RBTREE, +}; + +static const struct spi_device_id cs35l41_id_spi[] = { + {"cs35l40", 0}, + {"cs35l41", 0}, + {} +}; + +MODULE_DEVICE_TABLE(spi, cs35l41_id_spi); + +static int cs35l41_spi_probe(struct spi_device *spi) +{ + const struct regmap_config *regmap_config = &cs35l41_regmap_spi; + struct cs35l41_platform_data *pdata = + dev_get_platdata(&spi->dev); + struct cs35l41_private *cs35l41; + int ret; + + cs35l41 = devm_kzalloc(&spi->dev, + sizeof(struct cs35l41_private), + GFP_KERNEL); + if (cs35l41 == NULL) + return -ENOMEM; + + spi_set_drvdata(spi, cs35l41); + cs35l41->regmap = devm_regmap_init_spi(spi, regmap_config); + if (IS_ERR(cs35l41->regmap)) { + ret = PTR_ERR(cs35l41->regmap); + dev_err(&spi->dev, "Failed to allocate register map: %d\n", + ret); + return ret; + } + + cs35l41->dev = &spi->dev; + cs35l41->irq = spi->irq; + + return cs35l41_probe(cs35l41, pdata); +} + +static int cs35l41_spi_remove(struct spi_device *spi) +{ + struct cs35l41_private *cs35l41 = spi_get_drvdata(spi); + + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, 0xFFFFFFFF); + wm_adsp2_remove(&cs35l41->dsp); + regulator_bulk_disable(cs35l41->num_supplies, cs35l41->supplies); + snd_soc_unregister_codec(cs35l41->dev); + return 0; +} + +static const struct of_device_id cs35l41_of_match[] = { + {.compatible = "cirrus,cs35l40"}, + {.compatible = "cirrus,cs35l41"}, + {}, +}; +MODULE_DEVICE_TABLE(of, cs35l41_of_match); + +static struct spi_driver cs35l41_spi_driver = { + .driver = { + .name = "cs35l41", + .of_match_table = cs35l41_of_match, + }, + .id_table = cs35l41_id_spi, + .probe = cs35l41_spi_probe, + .remove = cs35l41_spi_remove, +}; + +module_spi_driver(cs35l41_spi_driver); + +MODULE_DESCRIPTION("SPI CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/techpack/audio/asoc/codecs/cs35l41/cs35l41-tables.c b/techpack/audio/asoc/codecs/cs35l41/cs35l41-tables.c new file mode 100644 index 000000000000..ec8c1eb1c5f7 --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/cs35l41-tables.c @@ -0,0 +1,945 @@ +/* + * cs35l41-tables.c -- CS35L41 ALSA SoC audio driver + * + * Copyright 2018 Cirrus Logic, Inc. + * + * Author: Brian Austin + * David Rhodes + * + * 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. + * + */ + +#include "cs35l41.h" + +const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG] = { + {CS35L41_TEST_KEY_CTL, 0x00000000}, + {CS35L41_USER_KEY_CTL, 0x00000000}, + {CS35L41_OTP_CTRL0, 0x00006418}, + {CS35L41_OTP_CTRL1, 0x00000000}, + {CS35L41_OTP_CTRL3, 0x00000000}, + {CS35L41_OTP_CTRL4, 0x00000000}, + {CS35L41_OTP_CTRL5, 0x00000030}, + {CS35L41_OTP_CTRL6, 0x00000000}, + {CS35L41_OTP_CTRL7, 0x00000000}, + {CS35L41_OTP_CTRL8, 0x00000000}, + {CS35L41_PWR_CTRL1, 0x00000000}, + {CS35L41_PWR_CTRL3, 0x01000010}, + {CS35L41_CTRL_OVRRIDE, 0x00000002}, + {CS35L41_AMP_OUT_MUTE, 0x00000000}, + {CS35L41_PROTECT_REL_ERR_IGN, 0x00000000}, + {CS35L41_GPIO_PAD_CONTROL, 0x00000000}, + {CS35L41_JTAG_CONTROL, 0x00000000}, + {CS35L41_PLL_CLK_CTRL, 0x00000010}, + {CS35L41_DSP_CLK_CTRL, 0x00000003}, + {CS35L41_GLOBAL_CLK_CTRL, 0x00000003}, + {CS35L41_DATA_FS_SEL, 0x00000000}, + {CS35L41_MDSYNC_EN, 0x00000200}, + {CS35L41_MDSYNC_TX_ID, 0x00000000}, + {CS35L41_MDSYNC_PWR_CTRL, 0x00000002}, + {CS35L41_MDSYNC_DATA_TX, 0x00000000}, + {CS35L41_MDSYNC_TX_STATUS, 0x00000002}, + {CS35L41_MDSYNC_DATA_RX, 0x00000000}, + {CS35L41_MDSYNC_RX_STATUS, 0x00000002}, + {CS35L41_MDSYNC_ERR_STATUS, 0x00000000}, + {CS35L41_MDSYNC_SYNC_PTE2, 0x00000000}, + {CS35L41_MDSYNC_SYNC_PTE3, 0x00000000}, + {CS35L41_MDSYNC_SYNC_MSM_STATUS, 0x00000000}, + {CS35L41_BSTCVRT_VCTRL1, 0x00000000}, + {CS35L41_BSTCVRT_VCTRL2, 0x00000001}, + {CS35L41_BSTCVRT_PEAK_CUR, 0x0000004A}, + {CS35L41_BSTCVRT_SFT_RAMP, 0x00000003}, + {CS35L41_BSTCVRT_COEFF, 0x00002424}, + {CS35L41_BSTCVRT_SLOPE_LBST, 0x00007500}, + {CS35L41_BSTCVRT_SW_FREQ, 0x01008000}, + {CS35L41_BSTCVRT_DCM_CTRL, 0x00002001}, + {CS35L41_BSTCVRT_DCM_MODE_FORCE, 0x00000000}, + {CS35L41_BSTCVRT_OVERVOLT_CTRL, 0x00000130}, + {CS35L41_VI_VOL_POL, 0x08000800}, + {CS35L41_DTEMP_WARN_THLD, 0x00000002}, + {CS35L41_DTEMP_EN, 0x00000000}, + {CS35L41_VPVBST_FS_SEL, 0x00000001}, + {CS35L41_SP_ENABLES, 0x00000000}, + {CS35L41_SP_RATE_CTRL, 0x00000028}, + {CS35L41_SP_FORMAT, 0x10100200}, + {CS35L41_SP_HIZ_CTRL, 0x00000002}, + {CS35L41_SP_FRAME_TX_SLOT, 0x03020100}, + {CS35L41_SP_FRAME_RX_SLOT, 0x00000100}, + {CS35L41_SP_TX_WL, 0x00000010}, + {CS35L41_SP_RX_WL, 0x00000018}, + {CS35L41_DAC_PCM1_SRC, 0x00000008}, + {CS35L41_ASP_TX1_SRC, 0x00000018}, + {CS35L41_ASP_TX2_SRC, 0x00000019}, + {CS35L41_ASP_TX3_SRC, 0x00000020}, + {CS35L41_ASP_TX4_SRC, 0x00000021}, + {CS35L41_DSP1_RX1_SRC, 0x00000008}, + {CS35L41_DSP1_RX2_SRC, 0x00000009}, + {CS35L41_DSP1_RX3_SRC, 0x00000018}, + {CS35L41_DSP1_RX4_SRC, 0x00000019}, + {CS35L41_DSP1_RX5_SRC, 0x00000020}, + {CS35L41_DSP1_RX6_SRC, 0x00000021}, + {CS35L41_DSP1_RX7_SRC, 0x0000003A}, + {CS35L41_DSP1_RX8_SRC, 0x00000001}, + {CS35L41_NGATE1_SRC, 0x00000008}, + {CS35L41_NGATE2_SRC, 0x00000009}, + {CS35L41_AMP_DIG_VOL_CTRL, 0x00008000}, + {CS35L41_VPBR_CFG, 0x02AA1905}, + {CS35L41_VBBR_CFG, 0x02AA1905}, + {CS35L41_VPBR_STATUS, 0x00000000}, + {CS35L41_VBBR_STATUS, 0x00000000}, + {CS35L41_OVERTEMP_CFG, 0x00000001}, + {CS35L41_AMP_ERR_VOL, 0x00000000}, + {CS35L41_VOL_STATUS_TO_DSP, 0x00000000}, + {CS35L41_CLASSH_CFG, 0x000B0405}, + {CS35L41_WKFET_CFG, 0x00000111}, + {CS35L41_NG_CFG, 0x00000033}, + {CS35L41_AMP_GAIN_CTRL, 0x00000273}, + {CS35L41_DAC_MSM_CFG, 0x00580000}, + {CS35L41_GPIO1_CTRL1, 0xE1000001}, + {CS35L41_GPIO2_CTRL1, 0xE1000001}, + {CS35L41_MIXER_NGATE_CFG, 0x00000000}, + {CS35L41_MIXER_NGATE_CH1_CFG, 0x00000303}, + {CS35L41_MIXER_NGATE_CH2_CFG, 0x00000303}, + {CS35L41_CLOCK_DETECT_1, 0x00000000}, + {CS35L41_TIMER1_CONTROL, 0x00000000}, + {CS35L41_TIMER1_COUNT_PRESET, 0x00000000}, + {CS35L41_TIMER1_START_STOP, 0x00000000}, + {CS35L41_TIMER1_STATUS, 0x00000000}, + {CS35L41_TIMER1_COUNT_READBACK, 0x00000000}, + {CS35L41_TIMER1_DSP_CLK_CFG, 0x00000000}, + {CS35L41_TIMER1_DSP_CLK_STATUS, 0x00000000}, + {CS35L41_TIMER2_CONTROL, 0x00000000}, + {CS35L41_TIMER2_COUNT_PRESET, 0x00000000}, + {CS35L41_TIMER2_START_STOP, 0x00000000}, + {CS35L41_TIMER2_STATUS, 0x00000000}, + {CS35L41_TIMER2_COUNT_READBACK, 0x00000000}, + {CS35L41_TIMER2_DSP_CLK_CFG, 0x00000000}, + {CS35L41_TIMER2_DSP_CLK_STATUS, 0x00000000}, + {CS35L41_DFT_JTAG_CONTROL, 0x00000000}, + {CS35L41_DIE_STS1, 0x00000000}, + {CS35L41_DIE_STS2, 0x00000000}, + {CS35L41_TEMP_CAL1, 0x00000000}, + {CS35L41_TEMP_CAL2, 0x00000000}, +}; + +bool cs35l41_readable_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_REVID: + case CS35L41_FABID: + case CS35L41_RELID: + case CS35L41_OTPID: + case CS35L41_TEST_KEY_CTL: + case CS35L41_USER_KEY_CTL: + case CS35L41_OTP_CTRL0: + case CS35L41_OTP_CTRL3: + case CS35L41_OTP_CTRL4: + case CS35L41_OTP_CTRL5: + case CS35L41_OTP_CTRL6: + case CS35L41_OTP_CTRL7: + case CS35L41_OTP_CTRL8: + case CS35L41_PWR_CTRL1: + case CS35L41_PWR_CTRL2: + case CS35L41_PWR_CTRL3: + case CS35L41_CTRL_OVRRIDE: + case CS35L41_AMP_OUT_MUTE: + case CS35L41_PROTECT_REL_ERR_IGN: + case CS35L41_GPIO_PAD_CONTROL: + case CS35L41_JTAG_CONTROL: + case CS35L41_PLL_CLK_CTRL: + case CS35L41_DSP_CLK_CTRL: + case CS35L41_GLOBAL_CLK_CTRL: + case CS35L41_DATA_FS_SEL: + case CS35L41_MDSYNC_EN: + case CS35L41_MDSYNC_TX_ID: + case CS35L41_MDSYNC_PWR_CTRL: + case CS35L41_MDSYNC_DATA_TX: + case CS35L41_MDSYNC_TX_STATUS: + case CS35L41_MDSYNC_DATA_RX: + case CS35L41_MDSYNC_RX_STATUS: + case CS35L41_MDSYNC_ERR_STATUS: + case CS35L41_MDSYNC_SYNC_PTE2: + case CS35L41_MDSYNC_SYNC_PTE3: + case CS35L41_MDSYNC_SYNC_MSM_STATUS: + case CS35L41_BSTCVRT_VCTRL1: + case CS35L41_BSTCVRT_VCTRL2: + case CS35L41_BSTCVRT_PEAK_CUR: + case CS35L41_BSTCVRT_SFT_RAMP: + case CS35L41_BSTCVRT_COEFF: + case CS35L41_BSTCVRT_SLOPE_LBST: + case CS35L41_BSTCVRT_SW_FREQ: + case CS35L41_BSTCVRT_DCM_CTRL: + case CS35L41_BSTCVRT_DCM_MODE_FORCE: + case CS35L41_BSTCVRT_OVERVOLT_CTRL: + case CS35L41_VI_VOL_POL: + case CS35L41_DTEMP_WARN_THLD: + case CS35L41_DTEMP_CFG: + case CS35L41_DTEMP_EN: + case CS35L41_VPVBST_FS_SEL: + case CS35L41_SP_ENABLES: + case CS35L41_SP_RATE_CTRL: + case CS35L41_SP_FORMAT: + case CS35L41_SP_HIZ_CTRL: + case CS35L41_SP_FRAME_TX_SLOT: + case CS35L41_SP_FRAME_RX_SLOT: + case CS35L41_SP_TX_WL: + case CS35L41_SP_RX_WL: + case CS35L41_DAC_PCM1_SRC: + case CS35L41_ASP_TX1_SRC: + case CS35L41_ASP_TX2_SRC: + case CS35L41_ASP_TX3_SRC: + case CS35L41_ASP_TX4_SRC: + case CS35L41_DSP1_RX1_SRC: + case CS35L41_DSP1_RX2_SRC: + case CS35L41_DSP1_RX3_SRC: + case CS35L41_DSP1_RX4_SRC: + case CS35L41_DSP1_RX5_SRC: + case CS35L41_DSP1_RX6_SRC: + case CS35L41_DSP1_RX7_SRC: + case CS35L41_DSP1_RX8_SRC: + case CS35L41_NGATE1_SRC: + case CS35L41_NGATE2_SRC: + case CS35L41_AMP_DIG_VOL_CTRL: + case CS35L41_VPBR_CFG: + case CS35L41_VBBR_CFG: + case CS35L41_VPBR_STATUS: + case CS35L41_VBBR_STATUS: + case CS35L41_OVERTEMP_CFG: + case CS35L41_AMP_ERR_VOL: + case CS35L41_VOL_STATUS_TO_DSP: + case CS35L41_CLASSH_CFG: + case CS35L41_WKFET_CFG: + case CS35L41_NG_CFG: + case CS35L41_AMP_GAIN_CTRL: + case CS35L41_DAC_MSM_CFG: + case CS35L41_IRQ1_CFG: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ1_MASK1: + case CS35L41_IRQ1_MASK2: + case CS35L41_IRQ1_MASK3: + case CS35L41_IRQ1_MASK4: + case CS35L41_IRQ1_FRC1: + case CS35L41_IRQ1_FRC2: + case CS35L41_IRQ1_FRC3: + case CS35L41_IRQ1_FRC4: + case CS35L41_IRQ1_EDGE1: + case CS35L41_IRQ1_EDGE4: + case CS35L41_IRQ1_POL1: + case CS35L41_IRQ1_POL2: + case CS35L41_IRQ1_POL3: + case CS35L41_IRQ1_POL4: + case CS35L41_IRQ1_DB3: + case CS35L41_IRQ2_CFG: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_IRQ2_MASK1: + case CS35L41_IRQ2_MASK2: + case CS35L41_IRQ2_MASK3: + case CS35L41_IRQ2_MASK4: + case CS35L41_IRQ2_FRC1: + case CS35L41_IRQ2_FRC2: + case CS35L41_IRQ2_FRC3: + case CS35L41_IRQ2_FRC4: + case CS35L41_IRQ2_EDGE1: + case CS35L41_IRQ2_EDGE4: + case CS35L41_IRQ2_POL1: + case CS35L41_IRQ2_POL2: + case CS35L41_IRQ2_POL3: + case CS35L41_IRQ2_POL4: + case CS35L41_IRQ2_DB3: + case CS35L41_GPIO_STATUS1: + case CS35L41_GPIO1_CTRL1: + case CS35L41_GPIO2_CTRL1: + case CS35L41_MIXER_NGATE_CFG: + case CS35L41_MIXER_NGATE_CH1_CFG: + case CS35L41_MIXER_NGATE_CH2_CFG: + case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: + case CS35L41_CLOCK_DETECT_1: + case CS35L41_TIMER1_CONTROL: + case CS35L41_TIMER1_COUNT_PRESET: + case CS35L41_TIMER1_STATUS: + case CS35L41_TIMER1_COUNT_READBACK: + case CS35L41_TIMER1_DSP_CLK_CFG: + case CS35L41_TIMER1_DSP_CLK_STATUS: + case CS35L41_TIMER2_CONTROL: + case CS35L41_TIMER2_COUNT_PRESET: + case CS35L41_TIMER2_STATUS: + case CS35L41_TIMER2_COUNT_READBACK: + case CS35L41_TIMER2_DSP_CLK_CFG: + case CS35L41_TIMER2_DSP_CLK_STATUS: + case CS35L41_DFT_JTAG_CONTROL: + case CS35L41_DIE_STS1: + case CS35L41_DIE_STS2: + case CS35L41_TEMP_CAL1: + case CS35L41_TEMP_CAL2: + case CS35L41_DSP1_TIMESTAMP_COUNT: + case CS35L41_DSP1_SYS_ID: + case CS35L41_DSP1_SYS_VERSION: + case CS35L41_DSP1_SYS_CORE_ID: + case CS35L41_DSP1_SYS_AHB_ADDR: + case CS35L41_DSP1_SYS_XSRAM_SIZE: + case CS35L41_DSP1_SYS_YSRAM_SIZE: + case CS35L41_DSP1_SYS_PSRAM_SIZE: + case CS35L41_DSP1_SYS_PM_BOOT_SIZE: + case CS35L41_DSP1_SYS_FEATURES: + case CS35L41_DSP1_SYS_FIR_FILTERS: + case CS35L41_DSP1_SYS_LMS_FILTERS: + case CS35L41_DSP1_SYS_XM_BANK_SIZE: + case CS35L41_DSP1_SYS_YM_BANK_SIZE: + case CS35L41_DSP1_SYS_PM_BANK_SIZE: + case CS35L41_DSP1_AHBM_WIN0_CTRL0: + case CS35L41_DSP1_AHBM_WIN0_CTRL1: + case CS35L41_DSP1_AHBM_WIN1_CTRL0: + case CS35L41_DSP1_AHBM_WIN1_CTRL1: + case CS35L41_DSP1_AHBM_WIN2_CTRL0: + case CS35L41_DSP1_AHBM_WIN2_CTRL1: + case CS35L41_DSP1_AHBM_WIN3_CTRL0: + case CS35L41_DSP1_AHBM_WIN3_CTRL1: + case CS35L41_DSP1_AHBM_WIN4_CTRL0: + case CS35L41_DSP1_AHBM_WIN4_CTRL1: + case CS35L41_DSP1_AHBM_WIN5_CTRL0: + case CS35L41_DSP1_AHBM_WIN5_CTRL1: + case CS35L41_DSP1_AHBM_WIN6_CTRL0: + case CS35L41_DSP1_AHBM_WIN6_CTRL1: + case CS35L41_DSP1_AHBM_WIN7_CTRL0: + case CS35L41_DSP1_AHBM_WIN7_CTRL1: + case CS35L41_DSP1_AHBM_WIN_DBG_CTRL0: + case CS35L41_DSP1_AHBM_WIN_DBG_CTRL1: + case CS35L41_DSP1_DEBUG: + case CS35L41_DSP1_TIMER_CTRL: + case CS35L41_DSP1_RX1_RATE: + case CS35L41_DSP1_RX2_RATE: + case CS35L41_DSP1_RX3_RATE: + case CS35L41_DSP1_RX4_RATE: + case CS35L41_DSP1_RX5_RATE: + case CS35L41_DSP1_RX6_RATE: + case CS35L41_DSP1_RX7_RATE: + case CS35L41_DSP1_RX8_RATE: + case CS35L41_DSP1_TX1_RATE: + case CS35L41_DSP1_TX2_RATE: + case CS35L41_DSP1_TX3_RATE: + case CS35L41_DSP1_TX4_RATE: + case CS35L41_DSP1_TX5_RATE: + case CS35L41_DSP1_TX6_RATE: + case CS35L41_DSP1_TX7_RATE: + case CS35L41_DSP1_TX8_RATE: + case CS35L41_DSP1_NMI_CTRL1: + case CS35L41_DSP1_NMI_CTRL2: + case CS35L41_DSP1_NMI_CTRL3: + case CS35L41_DSP1_NMI_CTRL4: + case CS35L41_DSP1_NMI_CTRL5: + case CS35L41_DSP1_NMI_CTRL6: + case CS35L41_DSP1_NMI_CTRL7: + case CS35L41_DSP1_NMI_CTRL8: + case CS35L41_DSP1_RESUME_CTRL: + case CS35L41_DSP1_IRQ1_CTRL: + case CS35L41_DSP1_IRQ2_CTRL: + case CS35L41_DSP1_IRQ3_CTRL: + case CS35L41_DSP1_IRQ4_CTRL: + case CS35L41_DSP1_IRQ5_CTRL: + case CS35L41_DSP1_IRQ6_CTRL: + case CS35L41_DSP1_IRQ7_CTRL: + case CS35L41_DSP1_IRQ8_CTRL: + case CS35L41_DSP1_IRQ9_CTRL: + case CS35L41_DSP1_IRQ10_CTRL: + case CS35L41_DSP1_IRQ11_CTRL: + case CS35L41_DSP1_IRQ12_CTRL: + case CS35L41_DSP1_IRQ13_CTRL: + case CS35L41_DSP1_IRQ14_CTRL: + case CS35L41_DSP1_IRQ15_CTRL: + case CS35L41_DSP1_IRQ16_CTRL: + case CS35L41_DSP1_IRQ17_CTRL: + case CS35L41_DSP1_IRQ18_CTRL: + case CS35L41_DSP1_IRQ19_CTRL: + case CS35L41_DSP1_IRQ20_CTRL: + case CS35L41_DSP1_IRQ21_CTRL: + case CS35L41_DSP1_IRQ22_CTRL: + case CS35L41_DSP1_IRQ23_CTRL: + case CS35L41_DSP1_SCRATCH1: + case CS35L41_DSP1_SCRATCH2: + case CS35L41_DSP1_SCRATCH3: + case CS35L41_DSP1_SCRATCH4: + case CS35L41_DSP1_CCM_CORE_CTRL: + case CS35L41_DSP1_CCM_CLK_OVERRIDE: + case CS35L41_DSP1_XM_MSTR_EN: + case CS35L41_DSP1_XM_CORE_PRI: + case CS35L41_DSP1_XM_AHB_PACK_PL_PRI: + case CS35L41_DSP1_XM_AHB_UP_PL_PRI: + case CS35L41_DSP1_XM_ACCEL_PL0_PRI: + case CS35L41_DSP1_XM_NPL0_PRI: + case CS35L41_DSP1_YM_MSTR_EN: + case CS35L41_DSP1_YM_CORE_PRI: + case CS35L41_DSP1_YM_AHB_PACK_PL_PRI: + case CS35L41_DSP1_YM_AHB_UP_PL_PRI: + case CS35L41_DSP1_YM_ACCEL_PL0_PRI: + case CS35L41_DSP1_YM_NPL0_PRI: + case CS35L41_DSP1_PM_MSTR_EN: + case CS35L41_DSP1_PM_PATCH0_ADDR: + case CS35L41_DSP1_PM_PATCH0_EN: + case CS35L41_DSP1_PM_PATCH0_DATA_LO: + case CS35L41_DSP1_PM_PATCH0_DATA_HI: + case CS35L41_DSP1_PM_PATCH1_ADDR: + case CS35L41_DSP1_PM_PATCH1_EN: + case CS35L41_DSP1_PM_PATCH1_DATA_LO: + case CS35L41_DSP1_PM_PATCH1_DATA_HI: + case CS35L41_DSP1_PM_PATCH2_ADDR: + case CS35L41_DSP1_PM_PATCH2_EN: + case CS35L41_DSP1_PM_PATCH2_DATA_LO: + case CS35L41_DSP1_PM_PATCH2_DATA_HI: + case CS35L41_DSP1_PM_PATCH3_ADDR: + case CS35L41_DSP1_PM_PATCH3_EN: + case CS35L41_DSP1_PM_PATCH3_DATA_LO: + case CS35L41_DSP1_PM_PATCH3_DATA_HI: + case CS35L41_DSP1_PM_PATCH4_ADDR: + case CS35L41_DSP1_PM_PATCH4_EN: + case CS35L41_DSP1_PM_PATCH4_DATA_LO: + case CS35L41_DSP1_PM_PATCH4_DATA_HI: + case CS35L41_DSP1_PM_PATCH5_ADDR: + case CS35L41_DSP1_PM_PATCH5_EN: + case CS35L41_DSP1_PM_PATCH5_DATA_LO: + case CS35L41_DSP1_PM_PATCH5_DATA_HI: + case CS35L41_DSP1_PM_PATCH6_ADDR: + case CS35L41_DSP1_PM_PATCH6_EN: + case CS35L41_DSP1_PM_PATCH6_DATA_LO: + case CS35L41_DSP1_PM_PATCH6_DATA_HI: + case CS35L41_DSP1_PM_PATCH7_ADDR: + case CS35L41_DSP1_PM_PATCH7_EN: + case CS35L41_DSP1_PM_PATCH7_DATA_LO: + case CS35L41_DSP1_PM_PATCH7_DATA_HI: + case CS35L41_DSP1_MPU_XM_ACCESS0: + case CS35L41_DSP1_MPU_YM_ACCESS0: + case CS35L41_DSP1_MPU_WNDW_ACCESS0: + case CS35L41_DSP1_MPU_XREG_ACCESS0: + case CS35L41_DSP1_MPU_YREG_ACCESS0: + case CS35L41_DSP1_MPU_XM_ACCESS1: + case CS35L41_DSP1_MPU_YM_ACCESS1: + case CS35L41_DSP1_MPU_WNDW_ACCESS1: + case CS35L41_DSP1_MPU_XREG_ACCESS1: + case CS35L41_DSP1_MPU_YREG_ACCESS1: + case CS35L41_DSP1_MPU_XM_ACCESS2: + case CS35L41_DSP1_MPU_YM_ACCESS2: + case CS35L41_DSP1_MPU_WNDW_ACCESS2: + case CS35L41_DSP1_MPU_XREG_ACCESS2: + case CS35L41_DSP1_MPU_YREG_ACCESS2: + case CS35L41_DSP1_MPU_XM_ACCESS3: + case CS35L41_DSP1_MPU_YM_ACCESS3: + case CS35L41_DSP1_MPU_WNDW_ACCESS3: + case CS35L41_DSP1_MPU_XREG_ACCESS3: + case CS35L41_DSP1_MPU_YREG_ACCESS3: + case CS35L41_DSP1_MPU_XM_VIO_ADDR: + case CS35L41_DSP1_MPU_XM_VIO_STATUS: + case CS35L41_DSP1_MPU_YM_VIO_ADDR: + case CS35L41_DSP1_MPU_YM_VIO_STATUS: + case CS35L41_DSP1_MPU_PM_VIO_ADDR: + case CS35L41_DSP1_MPU_PM_VIO_STATUS: + case CS35L41_DSP1_MPU_LOCK_CONFIG: + case CS35L41_DSP1_MPU_WDT_RST_CTRL: + case CS35L41_DSP1_STRMARB_MSTR0_CFG0: + case CS35L41_DSP1_STRMARB_MSTR0_CFG1: + case CS35L41_DSP1_STRMARB_MSTR0_CFG2: + case CS35L41_DSP1_STRMARB_MSTR1_CFG0: + case CS35L41_DSP1_STRMARB_MSTR1_CFG1: + case CS35L41_DSP1_STRMARB_MSTR1_CFG2: + case CS35L41_DSP1_STRMARB_MSTR2_CFG0: + case CS35L41_DSP1_STRMARB_MSTR2_CFG1: + case CS35L41_DSP1_STRMARB_MSTR2_CFG2: + case CS35L41_DSP1_STRMARB_MSTR3_CFG0: + case CS35L41_DSP1_STRMARB_MSTR3_CFG1: + case CS35L41_DSP1_STRMARB_MSTR3_CFG2: + case CS35L41_DSP1_STRMARB_MSTR4_CFG0: + case CS35L41_DSP1_STRMARB_MSTR4_CFG1: + case CS35L41_DSP1_STRMARB_MSTR4_CFG2: + case CS35L41_DSP1_STRMARB_MSTR5_CFG0: + case CS35L41_DSP1_STRMARB_MSTR5_CFG1: + case CS35L41_DSP1_STRMARB_MSTR5_CFG2: + case CS35L41_DSP1_STRMARB_MSTR6_CFG0: + case CS35L41_DSP1_STRMARB_MSTR6_CFG1: + case CS35L41_DSP1_STRMARB_MSTR6_CFG2: + case CS35L41_DSP1_STRMARB_MSTR7_CFG0: + case CS35L41_DSP1_STRMARB_MSTR7_CFG1: + case CS35L41_DSP1_STRMARB_MSTR7_CFG2: + case CS35L41_DSP1_STRMARB_TX0_CFG0: + case CS35L41_DSP1_STRMARB_TX0_CFG1: + case CS35L41_DSP1_STRMARB_TX1_CFG0: + case CS35L41_DSP1_STRMARB_TX1_CFG1: + case CS35L41_DSP1_STRMARB_TX2_CFG0: + case CS35L41_DSP1_STRMARB_TX2_CFG1: + case CS35L41_DSP1_STRMARB_TX3_CFG0: + case CS35L41_DSP1_STRMARB_TX3_CFG1: + case CS35L41_DSP1_STRMARB_TX4_CFG0: + case CS35L41_DSP1_STRMARB_TX4_CFG1: + case CS35L41_DSP1_STRMARB_TX5_CFG0: + case CS35L41_DSP1_STRMARB_TX5_CFG1: + case CS35L41_DSP1_STRMARB_TX6_CFG0: + case CS35L41_DSP1_STRMARB_TX6_CFG1: + case CS35L41_DSP1_STRMARB_TX7_CFG0: + case CS35L41_DSP1_STRMARB_TX7_CFG1: + case CS35L41_DSP1_STRMARB_RX0_CFG0: + case CS35L41_DSP1_STRMARB_RX0_CFG1: + case CS35L41_DSP1_STRMARB_RX1_CFG0: + case CS35L41_DSP1_STRMARB_RX1_CFG1: + case CS35L41_DSP1_STRMARB_RX2_CFG0: + case CS35L41_DSP1_STRMARB_RX2_CFG1: + case CS35L41_DSP1_STRMARB_RX3_CFG0: + case CS35L41_DSP1_STRMARB_RX3_CFG1: + case CS35L41_DSP1_STRMARB_RX4_CFG0: + case CS35L41_DSP1_STRMARB_RX4_CFG1: + case CS35L41_DSP1_STRMARB_RX5_CFG0: + case CS35L41_DSP1_STRMARB_RX5_CFG1: + case CS35L41_DSP1_STRMARB_RX6_CFG0: + case CS35L41_DSP1_STRMARB_RX6_CFG1: + case CS35L41_DSP1_STRMARB_RX7_CFG0: + case CS35L41_DSP1_STRMARB_RX7_CFG1: + case CS35L41_DSP1_STRMARB_IRQ0_CFG0: + case CS35L41_DSP1_STRMARB_IRQ0_CFG1: + case CS35L41_DSP1_STRMARB_IRQ0_CFG2: + case CS35L41_DSP1_STRMARB_IRQ1_CFG0: + case CS35L41_DSP1_STRMARB_IRQ1_CFG1: + case CS35L41_DSP1_STRMARB_IRQ1_CFG2: + case CS35L41_DSP1_STRMARB_IRQ2_CFG0: + case CS35L41_DSP1_STRMARB_IRQ2_CFG1: + case CS35L41_DSP1_STRMARB_IRQ2_CFG2: + case CS35L41_DSP1_STRMARB_IRQ3_CFG0: + case CS35L41_DSP1_STRMARB_IRQ3_CFG1: + case CS35L41_DSP1_STRMARB_IRQ3_CFG2: + case CS35L41_DSP1_STRMARB_IRQ4_CFG0: + case CS35L41_DSP1_STRMARB_IRQ4_CFG1: + case CS35L41_DSP1_STRMARB_IRQ4_CFG2: + case CS35L41_DSP1_STRMARB_IRQ5_CFG0: + case CS35L41_DSP1_STRMARB_IRQ5_CFG1: + case CS35L41_DSP1_STRMARB_IRQ5_CFG2: + case CS35L41_DSP1_STRMARB_IRQ6_CFG0: + case CS35L41_DSP1_STRMARB_IRQ6_CFG1: + case CS35L41_DSP1_STRMARB_IRQ6_CFG2: + case CS35L41_DSP1_STRMARB_IRQ7_CFG0: + case CS35L41_DSP1_STRMARB_IRQ7_CFG1: + case CS35L41_DSP1_STRMARB_IRQ7_CFG2: + case CS35L41_DSP1_STRMARB_RESYNC_MSK: + case CS35L41_DSP1_STRMARB_ERR_STATUS: + case CS35L41_DSP1_INTPCTL_RES_STATIC: + case CS35L41_DSP1_INTPCTL_RES_DYN: + case CS35L41_DSP1_INTPCTL_NMI_CTRL: + case CS35L41_DSP1_INTPCTL_IRQ_INV: + case CS35L41_DSP1_INTPCTL_IRQ_MODE: + case CS35L41_DSP1_INTPCTL_IRQ_EN: + case CS35L41_DSP1_INTPCTL_IRQ_MSK: + case CS35L41_DSP1_INTPCTL_IRQ_ERR: + case CS35L41_DSP1_INTPCTL_IRQ_PEND: + case CS35L41_DSP1_INTPCTL_TESTBITS: + case CS35L41_DSP1_WDT_CONTROL: + case CS35L41_DSP1_WDT_STATUS: + case CS35L41_OTP_TRIM_1: + case CS35L41_OTP_TRIM_2: + case CS35L41_OTP_TRIM_3: + case CS35L41_OTP_TRIM_4: + case CS35L41_OTP_TRIM_5: + case CS35L41_OTP_TRIM_6: + case CS35L41_OTP_TRIM_7: + case CS35L41_OTP_TRIM_8: + case CS35L41_OTP_TRIM_9: + case CS35L41_OTP_TRIM_10: + case CS35L41_OTP_TRIM_11: + case CS35L41_OTP_TRIM_12: + case CS35L41_OTP_TRIM_13: + case CS35L41_OTP_TRIM_14: + case CS35L41_OTP_TRIM_15: + case CS35L41_OTP_TRIM_16: + case CS35L41_OTP_TRIM_17: + case CS35L41_OTP_TRIM_18: + case CS35L41_OTP_TRIM_19: + case CS35L41_OTP_TRIM_20: + case CS35L41_OTP_TRIM_21: + case CS35L41_OTP_TRIM_22: + case CS35L41_OTP_TRIM_23: + case CS35L41_OTP_TRIM_24: + case CS35L41_OTP_TRIM_25: + case CS35L41_OTP_TRIM_26: + case CS35L41_OTP_TRIM_27: + case CS35L41_OTP_TRIM_28: + case CS35L41_OTP_TRIM_29: + case CS35L41_OTP_TRIM_30: + case CS35L41_OTP_TRIM_31: + case CS35L41_OTP_TRIM_32: + case CS35L41_OTP_TRIM_33: + case CS35L41_OTP_TRIM_34: + case CS35L41_OTP_TRIM_35: + case CS35L41_OTP_TRIM_36: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046: + case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022: + case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: + /*test regs*/ + case CS35L41_PLL_OVR: + case CS35L41_BST_TEST_DUTY: + case CS35L41_DIGPWM_IOCTRL: + return true; + default: + return false; + } +} + +bool cs35l41_precious_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + return true; + default: + return false; + } +} + +bool cs35l41_volatile_reg(struct device *dev, unsigned int reg) +{ + switch (reg) { + case CS35L41_DEVID: + case CS35L41_SFT_RESET: + case CS35L41_FABID: + case CS35L41_REVID: + case CS35L41_DTEMP_EN: + case CS35L41_IRQ1_STATUS: + case CS35L41_IRQ1_STATUS1: + case CS35L41_IRQ1_STATUS2: + case CS35L41_IRQ1_STATUS3: + case CS35L41_IRQ1_STATUS4: + case CS35L41_IRQ1_RAW_STATUS1: + case CS35L41_IRQ1_RAW_STATUS2: + case CS35L41_IRQ1_RAW_STATUS3: + case CS35L41_IRQ1_RAW_STATUS4: + case CS35L41_IRQ1_FRC1: + case CS35L41_IRQ1_FRC2: + case CS35L41_IRQ1_FRC3: + case CS35L41_IRQ1_FRC4: + case CS35L41_IRQ1_EDGE1: + case CS35L41_IRQ1_EDGE4: + case CS35L41_IRQ1_POL1: + case CS35L41_IRQ1_POL2: + case CS35L41_IRQ1_POL3: + case CS35L41_IRQ1_POL4: + case CS35L41_IRQ1_DB3: + case CS35L41_IRQ2_STATUS: + case CS35L41_IRQ2_STATUS1: + case CS35L41_IRQ2_STATUS2: + case CS35L41_IRQ2_STATUS3: + case CS35L41_IRQ2_STATUS4: + case CS35L41_IRQ2_RAW_STATUS1: + case CS35L41_IRQ2_RAW_STATUS2: + case CS35L41_IRQ2_RAW_STATUS3: + case CS35L41_IRQ2_RAW_STATUS4: + case CS35L41_IRQ2_FRC1: + case CS35L41_IRQ2_FRC2: + case CS35L41_IRQ2_FRC3: + case CS35L41_IRQ2_FRC4: + case CS35L41_IRQ2_EDGE1: + case CS35L41_IRQ2_EDGE4: + case CS35L41_IRQ2_POL1: + case CS35L41_IRQ2_POL2: + case CS35L41_IRQ2_POL3: + case CS35L41_IRQ2_POL4: + case CS35L41_IRQ2_DB3: + case CS35L41_GPIO_STATUS1: + case CS35L41_OTP_TRIM_1: + case CS35L41_OTP_TRIM_2: + case CS35L41_OTP_TRIM_3: + case CS35L41_OTP_TRIM_4: + case CS35L41_OTP_TRIM_5: + case CS35L41_OTP_TRIM_6: + case CS35L41_OTP_TRIM_7: + case CS35L41_OTP_TRIM_8: + case CS35L41_OTP_TRIM_9: + case CS35L41_OTP_TRIM_10: + case CS35L41_OTP_TRIM_11: + case CS35L41_OTP_TRIM_12: + case CS35L41_OTP_TRIM_13: + case CS35L41_OTP_TRIM_14: + case CS35L41_OTP_TRIM_15: + case CS35L41_OTP_TRIM_16: + case CS35L41_OTP_TRIM_17: + case CS35L41_OTP_TRIM_18: + case CS35L41_OTP_TRIM_19: + case CS35L41_OTP_TRIM_20: + case CS35L41_OTP_TRIM_21: + case CS35L41_OTP_TRIM_22: + case CS35L41_OTP_TRIM_23: + case CS35L41_OTP_TRIM_24: + case CS35L41_OTP_TRIM_25: + case CS35L41_OTP_TRIM_26: + case CS35L41_OTP_TRIM_27: + case CS35L41_OTP_TRIM_28: + case CS35L41_OTP_TRIM_29: + case CS35L41_OTP_TRIM_30: + case CS35L41_OTP_TRIM_31: + case CS35L41_OTP_TRIM_32: + case CS35L41_OTP_TRIM_33: + case CS35L41_OTP_TRIM_34: + case CS35L41_OTP_TRIM_35: + case CS35L41_OTP_TRIM_36: + case CS35L41_DSP_MBOX_1 ... CS35L41_DSP_VIRT2_MBOX_8: + case CS35L41_DSP1_XMEM_PACK_0 ... CS35L41_DSP1_XMEM_PACK_3068: + case CS35L41_DSP1_XMEM_UNPACK32_0 ... CS35L41_DSP1_XMEM_UNPACK32_2046: + case CS35L41_DSP1_XMEM_UNPACK24_0 ... CS35L41_DSP1_XMEM_UNPACK24_4093: + case CS35L41_DSP1_YMEM_PACK_0 ... CS35L41_DSP1_YMEM_PACK_1532: + case CS35L41_DSP1_YMEM_UNPACK32_0 ... CS35L41_DSP1_YMEM_UNPACK32_1022: + case CS35L41_DSP1_YMEM_UNPACK24_0 ... CS35L41_DSP1_YMEM_UNPACK24_2045: + case CS35L41_DSP1_PMEM_0 ... CS35L41_DSP1_PMEM_5114: + case CS35L41_DSP1_CCM_CORE_CTRL ... CS35L41_DSP1_WDT_STATUS: + case CS35L41_OTP_MEM0 ... CS35L41_OTP_MEM31: + return true; + default: + return false; + } +} + +static const struct cs35l41_otp_packed_element_t + otp_map_1[CS35L41_NUM_OTP_ELEM] = { + /* addr shift size */ + {0x00002030, 0, 4}, /*TRIM_OSC_FREQ_TRIM*/ + {0x00002030, 7, 1}, /*TRIM_OSC_TRIM_DONE*/ + {0x0000208c, 24, 6}, /*TST_DIGREG_VREF_TRIM*/ + {0x00002090, 14, 4}, /*TST_REF_TRIM*/ + {0x00002090, 10, 4}, /*TST_REF_TEMPCO_TRIM*/ + {0x0000300C, 11, 4}, /*PLL_LDOA_TST_VREF_TRIM*/ + {0x0000394C, 23, 2}, /*BST_ATEST_CM_VOFF*/ + {0x00003950, 0, 7}, /*BST_ATRIM_IADC_OFFSET*/ + {0x00003950, 8, 7}, /*BST_ATRIM_IADC_GAIN1*/ + {0x00003950, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + {0x00003950, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN1*/ + {0x00003954, 0, 7}, /*BST_ATRIM_IADC_OFFSET2*/ + {0x00003954, 8, 7}, /*BST_ATRIM_IADC_GAIN2*/ + {0x00003954, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + {0x00003954, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN2*/ + {0x00003958, 0, 7}, /*BST_ATRIM_IADC_OFFSET3*/ + {0x00003958, 8, 7}, /*BST_ATRIM_IADC_GAIN3*/ + {0x00003958, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + {0x00003958, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN3*/ + {0x0000395C, 0, 7}, /*BST_ATRIM_IADC_OFFSET4*/ + {0x0000395C, 8, 7}, /*BST_ATRIM_IADC_GAIN4*/ + {0x0000395C, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + {0x0000395C, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN4*/ + {0x0000416C, 0, 8}, /*VMON_GAIN_OTP_VAL*/ + {0x00004160, 0, 7}, /*VMON_OFFSET_OTP_VAL*/ + {0x0000416C, 8, 8}, /*IMON_GAIN_OTP_VAL*/ + {0x00004160, 16, 10}, /*IMON_OFFSET_OTP_VAL*/ + {0x0000416C, 16, 12}, /*VMON_CM_GAIN_OTP_VAL*/ + {0x0000416C, 28, 1}, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + {0x00004170, 0, 6}, /*IMON_CAL_TEMPCO_OTP_VAL*/ + {0x00004170, 6, 1}, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + {0x00004170, 8, 6}, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + {0x00004170, 14, 1}, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + {0x00004170, 16, 9}, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + {0x00004360, 0, 5}, /*TEMP_GAIN_OTP_VAL*/ + {0x00004360, 6, 9}, /*TEMP_OFFSET_OTP_VAL*/ + {0x00004448, 0, 8}, /*VP_SARADC_OFFSET*/ + {0x00004448, 8, 8}, /*VP_GAIN_INDEX*/ + {0x00004448, 16, 8}, /*VBST_SARADC_OFFSET*/ + {0x00004448, 24, 8}, /*VBST_GAIN_INDEX*/ + {0x0000444C, 0, 3}, /*ANA_SELINVREF*/ + {0x00006E30, 0, 5}, /*GAIN_ERR_COEFF_0*/ + {0x00006E30, 8, 5}, /*GAIN_ERR_COEFF_1*/ + {0x00006E30, 16, 5}, /*GAIN_ERR_COEFF_2*/ + {0x00006E30, 24, 5}, /*GAIN_ERR_COEFF_3*/ + {0x00006E34, 0, 5}, /*GAIN_ERR_COEFF_4*/ + {0x00006E34, 8, 5}, /*GAIN_ERR_COEFF_5*/ + {0x00006E34, 16, 5}, /*GAIN_ERR_COEFF_6*/ + {0x00006E34, 24, 5}, /*GAIN_ERR_COEFF_7*/ + {0x00006E38, 0, 5}, /*GAIN_ERR_COEFF_8*/ + {0x00006E38, 8, 5}, /*GAIN_ERR_COEFF_9*/ + {0x00006E38, 16, 5}, /*GAIN_ERR_COEFF_10*/ + {0x00006E38, 24, 5}, /*GAIN_ERR_COEFF_11*/ + {0x00006E3C, 0, 5}, /*GAIN_ERR_COEFF_12*/ + {0x00006E3C, 8, 5}, /*GAIN_ERR_COEFF_13*/ + {0x00006E3C, 16, 5}, /*GAIN_ERR_COEFF_14*/ + {0x00006E3C, 24, 5}, /*GAIN_ERR_COEFF_15*/ + {0x00006E40, 0, 5}, /*GAIN_ERR_COEFF_16*/ + {0x00006E40, 8, 5}, /*GAIN_ERR_COEFF_17*/ + {0x00006E40, 16, 5}, /*GAIN_ERR_COEFF_18*/ + {0x00006E40, 24, 5}, /*GAIN_ERR_COEFF_19*/ + {0x00006E44, 0, 5}, /*GAIN_ERR_COEFF_20*/ + {0x00006E48, 0, 10}, /*VOFF_GAIN_0*/ + {0x00006E48, 10, 10}, /*VOFF_GAIN_1*/ + {0x00006E48, 20, 10}, /*VOFF_GAIN_2*/ + {0x00006E4C, 0, 10}, /*VOFF_GAIN_3*/ + {0x00006E4C, 10, 10}, /*VOFF_GAIN_4*/ + {0x00006E4C, 20, 10}, /*VOFF_GAIN_5*/ + {0x00006E50, 0, 10}, /*VOFF_GAIN_6*/ + {0x00006E50, 10, 10}, /*VOFF_GAIN_7*/ + {0x00006E50, 20, 10}, /*VOFF_GAIN_8*/ + {0x00006E54, 0, 10}, /*VOFF_GAIN_9*/ + {0x00006E54, 10, 10}, /*VOFF_GAIN_10*/ + {0x00006E54, 20, 10}, /*VOFF_GAIN_11*/ + {0x00006E58, 0, 10}, /*VOFF_GAIN_12*/ + {0x00006E58, 10, 10}, /*VOFF_GAIN_13*/ + {0x00006E58, 20, 10}, /*VOFF_GAIN_14*/ + {0x00006E5C, 0, 10}, /*VOFF_GAIN_15*/ + {0x00006E5C, 10, 10}, /*VOFF_GAIN_16*/ + {0x00006E5C, 20, 10}, /*VOFF_GAIN_17*/ + {0x00006E60, 0, 10}, /*VOFF_GAIN_18*/ + {0x00006E60, 10, 10}, /*VOFF_GAIN_19*/ + {0x00006E60, 20, 10}, /*VOFF_GAIN_20*/ + {0x00006E64, 0, 10}, /*VOFF_INT1*/ + {0x00007418, 7, 5}, /*DS_SPK_INT1_CAP_TRIM*/ + {0x0000741C, 0, 5}, /*DS_SPK_INT2_CAP_TRIM*/ + {0x0000741C, 11, 4}, /*DS_SPK_LPF_CAP_TRIM*/ + {0x0000741C, 19, 4}, /*DS_SPK_QUAN_CAP_TRIM*/ + {0x00007434, 17, 1}, /*FORCE_CAL*/ + {0x00007434, 18, 7}, /*CAL_OVERRIDE*/ + {0x00007068, 0, 9}, /*MODIX*/ + {0x0000410C, 7, 1}, /*VIMON_DLY_NOT_COMB*/ + {0x0000400C, 0, 7}, /*VIMON_DLY*/ + {0x00000000, 0, 1}, /*extra bit*/ + {0x00017040, 0, 8}, /*X_COORDINATE*/ + {0x00017040, 8, 8}, /*Y_COORDINATE*/ + {0x00017040, 16, 8}, /*WAFER_ID*/ + {0x00017040, 24, 8}, /*DVS*/ + {0x00017044, 0, 24}, /*LOT_NUMBER*/ +}; + +static const struct cs35l41_otp_packed_element_t + otp_map_2[CS35L41_NUM_OTP_ELEM] = { + /* addr shift size */ + {0x00002030, 0, 4}, /*TRIM_OSC_FREQ_TRIM*/ + {0x00002030, 7, 1}, /*TRIM_OSC_TRIM_DONE*/ + {0x0000208c, 24, 6}, /*TST_DIGREG_VREF_TRIM*/ + {0x00002090, 14, 4}, /*TST_REF_TRIM*/ + {0x00002090, 10, 4}, /*TST_REF_TEMPCO_TRIM*/ + {0x0000300C, 11, 4}, /*PLL_LDOA_TST_VREF_TRIM*/ + {0x0000394C, 23, 2}, /*BST_ATEST_CM_VOFF*/ + {0x00003950, 0, 7}, /*BST_ATRIM_IADC_OFFSET*/ + {0x00003950, 8, 7}, /*BST_ATRIM_IADC_GAIN1*/ + {0x00003950, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET1*/ + {0x00003950, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN1*/ + {0x00003954, 0, 7}, /*BST_ATRIM_IADC_OFFSET2*/ + {0x00003954, 8, 7}, /*BST_ATRIM_IADC_GAIN2*/ + {0x00003954, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET2*/ + {0x00003954, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN2*/ + {0x00003958, 0, 7}, /*BST_ATRIM_IADC_OFFSET3*/ + {0x00003958, 8, 7}, /*BST_ATRIM_IADC_GAIN3*/ + {0x00003958, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET3*/ + {0x00003958, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN3*/ + {0x0000395C, 0, 7}, /*BST_ATRIM_IADC_OFFSET4*/ + {0x0000395C, 8, 7}, /*BST_ATRIM_IADC_GAIN4*/ + {0x0000395C, 16, 8}, /*BST_ATRIM_IPKCOMP_OFFSET4*/ + {0x0000395C, 24, 8}, /*BST_ATRIM_IPKCOMP_GAIN4*/ + {0x0000416C, 0, 8}, /*VMON_GAIN_OTP_VAL*/ + {0x00004160, 0, 7}, /*VMON_OFFSET_OTP_VAL*/ + {0x0000416C, 8, 8}, /*IMON_GAIN_OTP_VAL*/ + {0x00004160, 16, 10}, /*IMON_OFFSET_OTP_VAL*/ + {0x0000416C, 16, 12}, /*VMON_CM_GAIN_OTP_VAL*/ + {0x0000416C, 28, 1}, /*VMON_CM_GAIN_SIGN_OTP_VAL*/ + {0x00004170, 0, 6}, /*IMON_CAL_TEMPCO_OTP_VAL*/ + {0x00004170, 6, 1}, /*IMON_CAL_TEMPCO_SIGN_OTP*/ + {0x00004170, 8, 6}, /*IMON_CAL_TEMPCO2_OTP_VAL*/ + {0x00004170, 14, 1}, /*IMON_CAL_TEMPCO2_DN_UPB_OTP_VAL*/ + {0x00004170, 16, 9}, /*IMON_CAL_TEMPCO_TBASE_OTP_VAL*/ + {0x00004360, 0, 5}, /*TEMP_GAIN_OTP_VAL*/ + {0x00004360, 6, 9}, /*TEMP_OFFSET_OTP_VAL*/ + {0x00004448, 0, 8}, /*VP_SARADC_OFFSET*/ + {0x00004448, 8, 8}, /*VP_GAIN_INDEX*/ + {0x00004448, 16, 8}, /*VBST_SARADC_OFFSET*/ + {0x00004448, 24, 8}, /*VBST_GAIN_INDEX*/ + {0x0000444C, 0, 3}, /*ANA_SELINVREF*/ + {0x00006E30, 0, 5}, /*GAIN_ERR_COEFF_0*/ + {0x00006E30, 8, 5}, /*GAIN_ERR_COEFF_1*/ + {0x00006E30, 16, 5}, /*GAIN_ERR_COEFF_2*/ + {0x00006E30, 24, 5}, /*GAIN_ERR_COEFF_3*/ + {0x00006E34, 0, 5}, /*GAIN_ERR_COEFF_4*/ + {0x00006E34, 8, 5}, /*GAIN_ERR_COEFF_5*/ + {0x00006E34, 16, 5}, /*GAIN_ERR_COEFF_6*/ + {0x00006E34, 24, 5}, /*GAIN_ERR_COEFF_7*/ + {0x00006E38, 0, 5}, /*GAIN_ERR_COEFF_8*/ + {0x00006E38, 8, 5}, /*GAIN_ERR_COEFF_9*/ + {0x00006E38, 16, 5}, /*GAIN_ERR_COEFF_10*/ + {0x00006E38, 24, 5}, /*GAIN_ERR_COEFF_11*/ + {0x00006E3C, 0, 5}, /*GAIN_ERR_COEFF_12*/ + {0x00006E3C, 8, 5}, /*GAIN_ERR_COEFF_13*/ + {0x00006E3C, 16, 5}, /*GAIN_ERR_COEFF_14*/ + {0x00006E3C, 24, 5}, /*GAIN_ERR_COEFF_15*/ + {0x00006E40, 0, 5}, /*GAIN_ERR_COEFF_16*/ + {0x00006E40, 8, 5}, /*GAIN_ERR_COEFF_17*/ + {0x00006E40, 16, 5}, /*GAIN_ERR_COEFF_18*/ + {0x00006E40, 24, 5}, /*GAIN_ERR_COEFF_19*/ + {0x00006E44, 0, 5}, /*GAIN_ERR_COEFF_20*/ + {0x00006E48, 0, 10}, /*VOFF_GAIN_0*/ + {0x00006E48, 10, 10}, /*VOFF_GAIN_1*/ + {0x00006E48, 20, 10}, /*VOFF_GAIN_2*/ + {0x00006E4C, 0, 10}, /*VOFF_GAIN_3*/ + {0x00006E4C, 10, 10}, /*VOFF_GAIN_4*/ + {0x00006E4C, 20, 10}, /*VOFF_GAIN_5*/ + {0x00006E50, 0, 10}, /*VOFF_GAIN_6*/ + {0x00006E50, 10, 10}, /*VOFF_GAIN_7*/ + {0x00006E50, 20, 10}, /*VOFF_GAIN_8*/ + {0x00006E54, 0, 10}, /*VOFF_GAIN_9*/ + {0x00006E54, 10, 10}, /*VOFF_GAIN_10*/ + {0x00006E54, 20, 10}, /*VOFF_GAIN_11*/ + {0x00006E58, 0, 10}, /*VOFF_GAIN_12*/ + {0x00006E58, 10, 10}, /*VOFF_GAIN_13*/ + {0x00006E58, 20, 10}, /*VOFF_GAIN_14*/ + {0x00006E5C, 0, 10}, /*VOFF_GAIN_15*/ + {0x00006E5C, 10, 10}, /*VOFF_GAIN_16*/ + {0x00006E5C, 20, 10}, /*VOFF_GAIN_17*/ + {0x00006E60, 0, 10}, /*VOFF_GAIN_18*/ + {0x00006E60, 10, 10}, /*VOFF_GAIN_19*/ + {0x00006E60, 20, 10}, /*VOFF_GAIN_20*/ + {0x00006E64, 0, 10}, /*VOFF_INT1*/ + {0x00007418, 7, 5}, /*DS_SPK_INT1_CAP_TRIM*/ + {0x0000741C, 0, 5}, /*DS_SPK_INT2_CAP_TRIM*/ + {0x0000741C, 11, 4}, /*DS_SPK_LPF_CAP_TRIM*/ + {0x0000741C, 19, 4}, /*DS_SPK_QUAN_CAP_TRIM*/ + {0x00007434, 17, 1}, /*FORCE_CAL*/ + {0x00007434, 18, 7}, /*CAL_OVERRIDE*/ + {0x00007068, 0, 9}, /*MODIX*/ + {0x0000410C, 7, 1}, /*VIMON_DLY_NOT_COMB*/ + {0x0000400C, 0, 7}, /*VIMON_DLY*/ + {0x00004000, 11, 1}, /*VMON_POL*/ + {0x00017040, 0, 8}, /*X_COORDINATE*/ + {0x00017040, 8, 8}, /*Y_COORDINATE*/ + {0x00017040, 16, 8}, /*WAFER_ID*/ + {0x00017040, 24, 8}, /*DVS*/ + {0x00017044, 0, 24}, /*LOT_NUMBER*/ +}; + +const struct cs35l41_otp_map_element_t + cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS] = { + { + .id = 0x01, + .map = otp_map_1, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x02, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, + { + .id = 0x06, + .map = otp_map_2, + .num_elements = CS35L41_NUM_OTP_ELEM, + .bit_offset = 16, + .word_offset = 2, + }, +}; diff --git a/techpack/audio/asoc/codecs/cs35l41/cs35l41.c b/techpack/audio/asoc/codecs/cs35l41/cs35l41.c new file mode 100644 index 000000000000..edaddf38335d --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/cs35l41.c @@ -0,0 +1,2081 @@ +/* + * cs35l41.c -- CS35l41 ALSA SoC audio driver + * + * Copyright 2018 Cirrus Logic, Inc. + * + * Author: David Rhodes + * Brian Austin + * + * 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. + * + */ +#define DEBUG 1 +#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 "wm_adsp.h" +#include "cs35l41.h" +#include + +static const char * const cs35l41_supplies[] = { + "VA", + "VP", +}; + +struct cs35l41_pll_sysclk_config { + int freq; + int clk_cfg; +}; + +static const struct cs35l41_pll_sysclk_config cs35l41_pll_sysclk[] = { + { 32768, 0x00 }, + { 8000, 0x01 }, + { 11025, 0x02 }, + { 12000, 0x03 }, + { 16000, 0x04 }, + { 22050, 0x05 }, + { 24000, 0x06 }, + { 32000, 0x07 }, + { 44100, 0x08 }, + { 48000, 0x09 }, + { 88200, 0x0A }, + { 96000, 0x0B }, + { 128000, 0x0C }, + { 176400, 0x0D }, + { 192000, 0x0E }, + { 256000, 0x0F }, + { 352800, 0x10 }, + { 384000, 0x11 }, + { 512000, 0x12 }, + { 705600, 0x13 }, + { 750000, 0x14 }, + { 768000, 0x15 }, + { 1000000, 0x16 }, + { 1024000, 0x17 }, + { 1200000, 0x18 }, + { 1411200, 0x19 }, + { 1500000, 0x1A }, + { 1536000, 0x1B }, + { 2000000, 0x1C }, + { 2048000, 0x1D }, + { 2400000, 0x1E }, + { 2822400, 0x1F }, + { 3000000, 0x20 }, + { 3072000, 0x21 }, + { 3200000, 0x22 }, + { 4000000, 0x23 }, + { 4096000, 0x24 }, + { 4800000, 0x25 }, + { 5644800, 0x26 }, + { 6000000, 0x27 }, + { 6144000, 0x28 }, + { 6250000, 0x29 }, + { 6400000, 0x2A }, + { 6500000, 0x2B }, + { 6750000, 0x2C }, + { 7526400, 0x2D }, + { 8000000, 0x2E }, + { 8192000, 0x2F }, + { 9600000, 0x30 }, + { 11289600, 0x31 }, + { 12000000, 0x32 }, + { 12288000, 0x33 }, + { 12500000, 0x34 }, + { 12800000, 0x35 }, + { 13000000, 0x36 }, + { 13500000, 0x37 }, + { 19200000, 0x38 }, + { 22579200, 0x39 }, + { 24000000, 0x3A }, + { 24576000, 0x3B }, + { 25000000, 0x3C }, + { 25600000, 0x3D }, + { 26000000, 0x3E }, + { 27000000, 0x3F }, +}; + +static const unsigned char cs35l41_bst_k1_table[4][5] = { + {0x24, 0x32, 0x32, 0x4F, 0x57}, + {0x24, 0x32, 0x32, 0x4F, 0x57}, + {0x40, 0x32, 0x32, 0x4F, 0x57}, + {0x40, 0x32, 0x32, 0x4F, 0x57} +}; + +static const unsigned char cs35l41_bst_k2_table[4][5] = { + {0x24, 0x49, 0x66, 0xA3, 0xEA}, + {0x24, 0x49, 0x66, 0xA3, 0xEA}, + {0x48, 0x49, 0x66, 0xA3, 0xEA}, + {0x48, 0x49, 0x66, 0xA3, 0xEA} +}; + +static const unsigned char cs35l41_bst_slope_table[4] = { + 0x75, 0x6B, 0x3B, 0x28}; + +static int cs35l41_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, + int dir); + +static int cs35l41_dsp_power_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + if (cs35l41->halo_booted == false) + wm_halo_early_event(w, kcontrol, event); + else + cs35l41->dsp.booted = true; + + return 0; + case SND_SOC_DAPM_PRE_PMD: + if (cs35l41->halo_booted == false) { + wm_halo_early_event(w, kcontrol, event); + wm_halo_event(w, kcontrol, event); + } + default: + return 0; + } +} + +static int cs35l41_dsp_load_ev(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + if (cs35l41->halo_booted == false) { + wm_halo_event(w, kcontrol, event); + cs35l41->halo_booted = true; + } + default: + return 0; + } +} + +static int cs35l41_halo_booted_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = cs35l41->halo_booted; + + return 0; +} + +static int cs35l41_halo_booted_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + cs35l41->halo_booted = ucontrol->value.integer.value[0]; + + return 0; +} + +static int vendor_id_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = VENDOR_ID_NONE; + + if (cs35l41->pdata.spk_id_gpio_p) + ucontrol->value.integer.value[0] = spk_id_get(cs35l41->pdata.spk_id_gpio_p); + + return 0; +} + +static const DECLARE_TLV_DB_RANGE(dig_vol_tlv, + 0, 0, TLV_DB_SCALE_ITEM(TLV_DB_GAIN_MUTE, 0, 1), + 1, 913, TLV_DB_SCALE_ITEM(-10200, 25, 0)); +static DECLARE_TLV_DB_SCALE(amp_gain_tlv, 0, 1, 1); + +static const struct snd_kcontrol_new dre_ctrl = + SOC_DAPM_SINGLE("Switch", CS35L41_PWR_CTRL3, 20, 1, 0); + +static const char * const cs35l41_pcm_sftramp_text[] = { + "Off", ".5ms", "1ms", "2ms", "4ms", "8ms", "15ms", "30ms"}; + +static SOC_ENUM_SINGLE_DECL(pcm_sft_ramp, + CS35L41_AMP_DIG_VOL_CTRL, 0, + cs35l41_pcm_sftramp_text); + +static const char * const cs35l41_cspl_cmd_text[] = { + "CSPL_MBOX_CMD_RESUME", + "CSPL_MBOX_CMD_REINIT", + "CSPL_MBOX_CMD_STOP_PRE_REINIT", +}; + +static const unsigned int cs35l41_cspl_cmd_val[] = { + (unsigned int)CSPL_MBOX_CMD_RESUME, + (unsigned int)CSPL_MBOX_CMD_REINIT, + (unsigned int)CSPL_MBOX_CMD_STOP_PRE_REINIT, +}; + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_cspl_cmd, SND_SOC_NOPM, 0, 0, + cs35l41_cspl_cmd_text, cs35l41_cspl_cmd_val); + +static bool cs35l41_is_csplmboxsts_correct(enum cs35l41_cspl_mboxcmd cmd, + enum cs35l41_cspl_mboxstate sts) +{ + switch (cmd) { + case CSPL_MBOX_CMD_NONE: + case CSPL_MBOX_CMD_UNKNOWN_CMD: + return true; + case CSPL_MBOX_CMD_PAUSE: + return (sts == CSPL_MBOX_STS_PAUSED); + case CSPL_MBOX_CMD_RESUME: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_REINIT: + return (sts == CSPL_MBOX_STS_RUNNING); + case CSPL_MBOX_CMD_STOP_PRE_REINIT: + return (sts == CSPL_MBOX_STS_RDY_FOR_REINIT); + default: + return false; + } +} + +static int cs35l41_set_csplmboxcmd(struct cs35l41_private *cs35l41, + enum cs35l41_cspl_mboxcmd cmd) +{ + int ret; + unsigned int sts; + + /* Reset DSP sticky bit */ + regmap_write(cs35l41->regmap, CS35L41_IRQ2_STATUS2, + 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT); + + /* Reset AP sticky bit */ + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS2, + 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT); + + /* + * Set mailbox cmd + */ + reinit_completion(&cs35l41->mbox_cmd); + /* Unmask DSP INT */ + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2, + 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT, 0); + /* Unmask AP INT */ + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2, + 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT, 0); + regmap_write(cs35l41->regmap, CS35L41_CSPL_MBOX_CMD_DRV, cmd); + ret = wait_for_completion_timeout(&cs35l41->mbox_cmd, + msecs_to_jiffies(CS35L41_MBOXWAIT)); + if (ret == 0) { + dev_err(cs35l41->dev, + "Timout waiting for DSP to set mbox cmd\n"); + ret = -ETIMEDOUT; + } + + /* Mask AP INT */ + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK2, + 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT, + 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT); + /* Mask DSP INT */ + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ2_MASK2, + 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT, + 1 << CS35L41_CSPL_MBOX_CMD_DRV_SHIFT); + + if (regmap_read(cs35l41->regmap, + CS35L41_CSPL_MBOX_STS, &sts) < 0) { + dev_err(cs35l41->dev, "Failed to read %u\n", + CS35L41_CSPL_MBOX_STS); + ret = -EACCES; + } + + if (!cs35l41_is_csplmboxsts_correct(cmd, + (enum cs35l41_cspl_mboxstate)sts)) { + dev_err(cs35l41->dev, + "Failed to set mailbox(cmd: %u, sts: %u)\n", cmd, sts); + ret = -ENOMSG; + } + + return ret; +} + +static int cs35l41_cspl_cmd_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + struct soc_enum *soc_enum; + unsigned int i = ucontrol->value.enumerated.item[0]; + + soc_enum = (struct soc_enum *)kcontrol->private_value; + + if (i >= soc_enum->items) { + dev_err(codec->dev, "Invalid mixer input (%u)\n", i); + return -EINVAL; + } + + cs35l41->cspl_cmd = soc_enum->values[i]; + + return 0; +} + +static int cs35l41_cspl_cmd_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + struct soc_enum *soc_enum; + unsigned int i; + int ret = 0; + + soc_enum = (struct soc_enum *)kcontrol->private_value; + + for (i = 0; i < soc_enum->items; i++) { + if (cs35l41->cspl_cmd == soc_enum->values[i]) + break; + } + + if (i >= soc_enum->items) { + /* Cannot find value */ + dev_err(cs35l41->dev, "Cannot find cspl cmd\n"); + i = 0; + ret = -EINVAL; + } + + ucontrol->value.enumerated.item[0] = i; + + return ret; +} +static const char *virt_text[] = { "None", "Ref"}; +static SOC_ENUM_SINGLE_DECL(virt_enum, + SND_SOC_NOPM, 2, virt_text); + +static const struct snd_kcontrol_new virt_mux = + SOC_DAPM_ENUM("Virt Connect", virt_enum); + +static const char * const cs35l41_pcm_source_texts[] = {"None", "ASP", "DSP"}; +static const unsigned int cs35l41_pcm_source_values[] = {0x00, 0x08, 0x32}; +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_pcm_source_enum, + CS35L41_DAC_PCM1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_pcm_source_texts, + cs35l41_pcm_source_values); + +static const struct snd_kcontrol_new pcm_source_mux = + SOC_DAPM_ENUM("PCM Source", cs35l41_pcm_source_enum); + +static const char * const cs35l41_tx_input_texts[] = {"Zero", "ASPRX1", + "ASPRX2", "VMON", + "IMON", "VPMON", + "DSPTX1", "DSPTX2"}; +static const unsigned int cs35l41_tx_input_values[] = {0x00, + CS35L41_INPUT_SRC_ASPRX1, + CS35L41_INPUT_SRC_ASPRX2, + CS35L41_INPUT_SRC_VMON, + CS35L41_INPUT_SRC_IMON, + CS35L41_INPUT_SRC_VPMON, + CS35L41_INPUT_DSP_TX1, + CS35L41_INPUT_DSP_TX2}; + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx1_enum, + CS35L41_ASP_TX1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx1_mux = + SOC_DAPM_ENUM("ASPTX1 SRC", cs35l41_asptx1_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx2_enum, + CS35L41_ASP_TX2_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx2_mux = + SOC_DAPM_ENUM("ASPTX2 SRC", cs35l41_asptx2_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx3_enum, + CS35L41_ASP_TX3_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx3_mux = + SOC_DAPM_ENUM("ASPTX3 SRC", cs35l41_asptx3_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_asptx4_enum, + CS35L41_ASP_TX4_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new asp_tx4_mux = + SOC_DAPM_ENUM("ASPTX4 SRC", cs35l41_asptx4_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx1_enum, + CS35L41_DSP1_RX1_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new dsp_rx1_mux = + SOC_DAPM_ENUM("DSPRX1 SRC", cs35l41_dsprx1_enum); + +static SOC_VALUE_ENUM_SINGLE_DECL(cs35l41_dsprx2_enum, + CS35L41_DSP1_RX2_SRC, + 0, CS35L41_ASP_SOURCE_MASK, + cs35l41_tx_input_texts, + cs35l41_tx_input_values); + +static const struct snd_kcontrol_new dsp_rx2_mux = + SOC_DAPM_ENUM("DSPRX2 SRC", cs35l41_dsprx2_enum); + +static const char *const vendor_id_text[] = {"None", "AAC", "SSI", "GOER", "Unknown"}; +static const struct soc_enum vendor_id[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(vendor_id_text), vendor_id_text), +}; + +static const struct snd_kcontrol_new cs35l41_aud_controls[] = { + SOC_SINGLE_SX_TLV("Digital PCM Volume", CS35L41_AMP_DIG_VOL_CTRL, + 3, 0x4CF, 0x391, dig_vol_tlv), + SOC_SINGLE_TLV("AMP PCM Gain", CS35L41_AMP_GAIN_CTRL, 5, 0x14, 0, + amp_gain_tlv), + SOC_SINGLE_RANGE("ASPTX1 Slot Position", CS35L41_SP_FRAME_TX_SLOT, 0, + 0, 7, 0), + SOC_SINGLE_RANGE("ASPTX2 Slot Position", CS35L41_SP_FRAME_TX_SLOT, 8, + 0, 7, 0), + SOC_SINGLE_RANGE("ASPTX3 Slot Position", CS35L41_SP_FRAME_TX_SLOT, 16, + 0, 7, 0), + SOC_SINGLE_RANGE("ASPTX4 Slot Position", CS35L41_SP_FRAME_TX_SLOT, 24, + 0, 7, 0), + SOC_SINGLE_RANGE("ASPRX1 Slot Position", CS35L41_SP_FRAME_RX_SLOT, 0, + 0, 7, 0), + SOC_SINGLE_RANGE("ASPRX2 Slot Position", CS35L41_SP_FRAME_RX_SLOT, 8, + 0, 7, 0), + SOC_ENUM("PCM Soft Ramp", pcm_sft_ramp), + SOC_VALUE_ENUM_EXT("CSPL Command", cs35l41_cspl_cmd, + cs35l41_cspl_cmd_get, cs35l41_cspl_cmd_put), + SOC_SINGLE_EXT("DSP Booted", SND_SOC_NOPM, 0, 1, 0, + cs35l41_halo_booted_get, cs35l41_halo_booted_put), + WM_ADSP2_PRELOAD_SWITCH("DSP1", 1), + SOC_ENUM_EXT("SPK ID", vendor_id, vendor_id_get, NULL), +}; + +static const struct cs35l41_otp_map_element_t *cs35l41_find_otp_map(u32 otp_id) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_otp_map_map); i++) { + if (cs35l41_otp_map_map[i].id == otp_id) + return &cs35l41_otp_map_map[i]; + } + + return NULL; +} + +static int cs35l41_otp_unpack(void *data) +{ + struct cs35l41_private *cs35l41 = data; + u32 otp_mem[32]; + int i; + int bit_offset, word_offset; + unsigned int bit_sum = 8; + u32 otp_val, otp_id_reg; + const struct cs35l41_otp_map_element_t *otp_map_match; + const struct cs35l41_otp_packed_element_t *otp_map; + int ret; + struct spi_device *spi = NULL; + u32 orig_spi_freq = 0; + + ret = regmap_read(cs35l41->regmap, CS35L41_OTPID, &otp_id_reg); + if (ret < 0) { + dev_err(cs35l41->dev, "Read OTP ID failed\n"); + return -EINVAL; + } + + otp_map_match = cs35l41_find_otp_map(otp_id_reg); + + if (otp_map_match == NULL) { + dev_err(cs35l41->dev, "OTP Map matching ID %d not found\n", + otp_id_reg); + return -EINVAL; + } + + if (cs35l41->bus_spi) { + spi = to_spi_device(cs35l41->dev); + orig_spi_freq = spi->max_speed_hz; + spi->max_speed_hz = CS35L41_SPI_MAX_FREQ_OTP; + spi_setup(spi); + } + + #define MAX_BULK_READ_SIZE 4 + for (i = 0; i < CS35L41_OTP_SIZE_WORDS / MAX_BULK_READ_SIZE; i++) { + ret = regmap_bulk_read(cs35l41->regmap, CS35L41_OTP_MEM0 + i * 4 * MAX_BULK_READ_SIZE, + &otp_mem[i * MAX_BULK_READ_SIZE], MAX_BULK_READ_SIZE); + } + + if (ret < 0) { + dev_err(cs35l41->dev, "Read OTP Mem failed\n"); + return -EINVAL; + } + + if (cs35l41->bus_spi) { + spi->max_speed_hz = orig_spi_freq; + spi_setup(spi); + } + + otp_map = otp_map_match->map; + + bit_offset = otp_map_match->bit_offset; + word_offset = otp_map_match->word_offset; + + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000055); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Unlock key failed 1/2\n"); + return -EINVAL; + } + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000AA); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Unlock key failed 2/2\n"); + return -EINVAL; + } + + for (i = 0; i < otp_map_match->num_elements; i++) { + dev_dbg(cs35l41->dev, "bitoffset= %d, word_offset=%d, bit_sum mod 32=%d\n", + bit_offset, word_offset, bit_sum % 32); + if (bit_offset + otp_map[i].size - 1 >= 32) { + otp_val = (otp_mem[word_offset] & + GENMASK(31, bit_offset)) >> + bit_offset; + otp_val |= (otp_mem[++word_offset] & + GENMASK(bit_offset + + otp_map[i].size - 33, 0)) << + (32 - bit_offset); + bit_offset += otp_map[i].size - 32; + } else { + + otp_val = (otp_mem[word_offset] & + GENMASK(bit_offset + otp_map[i].size - 1, + bit_offset)) >> bit_offset; + bit_offset += otp_map[i].size; + } + bit_sum += otp_map[i].size; + + if (bit_offset == 32) { + bit_offset = 0; + word_offset++; + } + + if (otp_map[i].reg != 0) { + ret = regmap_update_bits(cs35l41->regmap, + otp_map[i].reg, + GENMASK(otp_map[i].shift + + otp_map[i].size - 1, + otp_map[i].shift), + otp_val << otp_map[i].shift); + if (ret < 0) { + dev_err(cs35l41->dev, "Write OTP val failed\n"); + return -EINVAL; + } + } + } + + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x000000CC); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Lock key failed 1/2\n"); + return -EINVAL; + } + ret = regmap_write(cs35l41->regmap, CS35L41_TEST_KEY_CTL, 0x00000033); + if (ret < 0) { + dev_err(cs35l41->dev, "Write Lock key failed 2/2\n"); + return -EINVAL; + } + + return 0; +} + +static irqreturn_t cs35l41_irq(int irq, void *data) +{ + struct cs35l41_private *cs35l41 = data; + unsigned int status[4]; + unsigned int masks[4]; + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(status); i++) { + regmap_read(cs35l41->regmap, + CS35L41_IRQ1_STATUS1 + (i * CS35L41_REGSTRIDE), + &status[i]); + regmap_read(cs35l41->regmap, + CS35L41_IRQ1_MASK1 + (i * CS35L41_REGSTRIDE), + &masks[i]); + } + + /* Check to see if unmasked bits are active */ + if (!(status[0] & ~masks[0]) && !(status[1] & ~masks[1]) && + !(status[2] & ~masks[2]) && !(status[3] & ~masks[3])) + return IRQ_NONE; + + if (status[1] & (1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT)) { + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS2, + 1 << CS35L41_CSPL_MBOX_CMD_FW_SHIFT); + complete(&cs35l41->mbox_cmd); + } + + if (status[0] & CS35L41_PUP_DONE_MASK) { + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_PUP_DONE_MASK); + complete(&cs35l41->global_pup_done); + } + + if (status[0] & CS35L41_PDN_DONE_MASK) { + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_PDN_DONE_MASK); + complete(&cs35l41->global_pdn_done); + } + + /* + * The following interrupts require a + * protection release cycle to get the + * speaker out of Safe-Mode. + */ + if (status[0] & CS35L41_AMP_SHORT_ERR) { + dev_crit(cs35l41->dev, "Amp short error\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_AMP_SHORT_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_AMP_SHORT_ERR_RLS, + CS35L41_AMP_SHORT_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_AMP_SHORT_ERR_RLS, 0); + } + + if (status[0] & CS35L41_TEMP_WARN) { + dev_crit(cs35l41->dev, "Over temperature warning\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_TEMP_WARN); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_WARN_ERR_RLS, + CS35L41_TEMP_WARN_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_WARN_ERR_RLS, 0); + } + + if (status[0] & CS35L41_TEMP_ERR) { + dev_crit(cs35l41->dev, "Over temperature error\n"); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_TEMP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_ERR_RLS, + CS35L41_TEMP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_TEMP_ERR_RLS, 0); + } + + if (status[0] & CS35L41_BST_OVP_ERR) { + dev_crit(cs35l41->dev, "VBST Over Voltage error\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_OVP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_OVP_ERR_RLS, + CS35L41_BST_OVP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_OVP_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << + CS35L41_BST_EN_SHIFT); + } + + if (status[0] & CS35L41_BST_DCM_UVP_ERR) { + dev_crit(cs35l41->dev, "DCM VBST Under Voltage Error\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_DCM_UVP_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_UVP_ERR_RLS, + CS35L41_BST_UVP_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_UVP_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << + CS35L41_BST_EN_SHIFT); + } + + if (status[0] & CS35L41_BST_SHORT_ERR) { + dev_crit(cs35l41->dev, "LBST error: powering off!\n"); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, 0); + regmap_write(cs35l41->regmap, CS35L41_IRQ1_STATUS1, + CS35L41_BST_SHORT_ERR); + regmap_write(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_SHORT_ERR_RLS, + CS35L41_BST_SHORT_ERR_RLS); + regmap_update_bits(cs35l41->regmap, CS35L41_PROTECT_REL_ERR_IGN, + CS35L41_BST_SHORT_ERR_RLS, 0); + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL2, + CS35L41_BST_EN_MASK, + CS35L41_BST_EN_DEFAULT << + CS35L41_BST_EN_SHIFT); + } + + if (status[3] & CS35L41_OTP_BOOT_DONE) { + regmap_update_bits(cs35l41->regmap, CS35L41_IRQ1_MASK4, + CS35L41_OTP_BOOT_DONE, CS35L41_OTP_BOOT_DONE); + } + + return IRQ_HANDLED; +} + +static const struct reg_sequence cs35l41_pup_patch[] = { + {0x00000040, 0x00000055}, + {0x00000040, 0x000000AA}, + {0x00002084, 0x002F1AA0}, + {0x00000040, 0x000000CC}, + {0x00000040, 0x00000033}, +}; + +static const struct reg_sequence cs35l41_pdn_patch[] = { + {0x00000040, 0x00000055}, + {0x00000040, 0x000000AA}, + {0x00002084, 0x002F1AA3}, + {0x00000040, 0x000000CC}, + {0x00000040, 0x00000033}, +}; + +static int cs35l41_main_amp_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + pr_debug("++++>CSPL: %s, event = %d.\n", __func__, event); + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_multi_reg_write_bypassed(cs35l41->regmap, + cs35l41_pup_patch, + ARRAY_SIZE(cs35l41_pup_patch)); + + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, + CS35L41_GLOBAL_EN_MASK, + 1 << CS35L41_GLOBAL_EN_SHIFT); + + usleep_range(1000, 1100); + + if (cs35l41->halo_booted) { + if (cs35l41->cspl_cmd == CSPL_MBOX_CMD_STOP_PRE_REINIT) + /* Send this command on power down event */ + ret = cs35l41_set_csplmboxcmd(cs35l41, + CSPL_MBOX_CMD_RESUME); + else + ret = cs35l41_set_csplmboxcmd(cs35l41, + cs35l41->cspl_cmd); + } + break; + case SND_SOC_DAPM_POST_PMD: + if (cs35l41->halo_booted) { + if (cs35l41->cspl_cmd == CSPL_MBOX_CMD_STOP_PRE_REINIT) + ret = cs35l41_set_csplmboxcmd(cs35l41, + cs35l41->cspl_cmd); + else + ret = cs35l41_set_csplmboxcmd(cs35l41, + CSPL_MBOX_CMD_PAUSE); + } + + regmap_update_bits(cs35l41->regmap, CS35L41_PWR_CTRL1, + CS35L41_GLOBAL_EN_MASK, 0); + + usleep_range(1000, 1100); + + regmap_multi_reg_write_bypassed(cs35l41->regmap, + cs35l41_pdn_patch, + ARRAY_SIZE(cs35l41_pdn_patch)); + break; + default: + dev_err(codec->dev, "Invalid event = 0x%x\n", event); + ret = -EINVAL; + } + pr_debug("----CSPL: %s.\n", __func__); + return ret; +} + +static const struct snd_soc_dapm_widget cs35l41_dapm_widgets[] = { + + SND_SOC_DAPM_SPK("DSP1 Preload", NULL), + SND_SOC_DAPM_SUPPLY_S("DSP1 Preloader", 100, + SND_SOC_NOPM, 0, 0, cs35l41_dsp_power_ev, + SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD), + SND_SOC_DAPM_OUT_DRV_E("DSP1", SND_SOC_NOPM, 0, 0, NULL, 0, + cs35l41_dsp_load_ev, SND_SOC_DAPM_POST_PMU), + SND_SOC_DAPM_OUTPUT("SPK"), + + SND_SOC_DAPM_AIF_IN("ASPRX1", NULL, 0, CS35L41_SP_ENABLES, 16, 0), + SND_SOC_DAPM_AIF_IN("ASPRX2", NULL, 0, CS35L41_SP_ENABLES, 17, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX1", NULL, 0, CS35L41_SP_ENABLES, 0, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX2", NULL, 0, CS35L41_SP_ENABLES, 1, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX3", NULL, 0, CS35L41_SP_ENABLES, 2, 0), + SND_SOC_DAPM_AIF_OUT("ASPTX4", NULL, 0, CS35L41_SP_ENABLES, 3, 0), + + SND_SOC_DAPM_ADC("VMON ADC", NULL, CS35L41_PWR_CTRL2, 12, 0), + SND_SOC_DAPM_ADC("IMON ADC", NULL, CS35L41_PWR_CTRL2, 13, 0), + SND_SOC_DAPM_ADC("VPMON ADC", NULL, CS35L41_PWR_CTRL2, 8, 0), + SND_SOC_DAPM_ADC("VBSTMON ADC", NULL, CS35L41_PWR_CTRL2, 9, 0), + SND_SOC_DAPM_ADC("TEMPMON ADC", NULL, CS35L41_PWR_CTRL2, 10, 0), + SND_SOC_DAPM_ADC("CLASS H", NULL, CS35L41_PWR_CTRL3, 4, 0), + + SND_SOC_DAPM_OUT_DRV_E("Main AMP", CS35L41_PWR_CTRL2, 0, 0, NULL, 0, + cs35l41_main_amp_event, + SND_SOC_DAPM_POST_PMD | SND_SOC_DAPM_POST_PMU), + + SND_SOC_DAPM_INPUT("VP"), + SND_SOC_DAPM_INPUT("VBST"), + SND_SOC_DAPM_INPUT("ISENSE"), + SND_SOC_DAPM_INPUT("VSENSE"), + SND_SOC_DAPM_INPUT("TEMP"), + + SND_SOC_DAPM_MUX("ASPTX Ref", SND_SOC_NOPM, 0, 0, &virt_mux), + SND_SOC_DAPM_MUX("ASP TX1 Source", SND_SOC_NOPM, 0, 0, &asp_tx1_mux), + SND_SOC_DAPM_MUX("ASP TX2 Source", SND_SOC_NOPM, 0, 0, &asp_tx2_mux), + SND_SOC_DAPM_MUX("ASP TX3 Source", SND_SOC_NOPM, 0, 0, &asp_tx3_mux), + SND_SOC_DAPM_MUX("ASP TX4 Source", SND_SOC_NOPM, 0, 0, &asp_tx4_mux), + SND_SOC_DAPM_MUX("DSP RX1 Source", SND_SOC_NOPM, 0, 0, &dsp_rx1_mux), + SND_SOC_DAPM_MUX("DSP RX2 Source", SND_SOC_NOPM, 0, 0, &dsp_rx2_mux), + SND_SOC_DAPM_MUX("PCM Source", SND_SOC_NOPM, 0, 0, &pcm_source_mux), + SND_SOC_DAPM_SWITCH("DRE", SND_SOC_NOPM, 0, 0, &dre_ctrl), + +}; + +static const struct snd_soc_dapm_route cs35l41_audio_map[] = { + + { "DSP1", NULL, "DSP1 Preloader" }, + { "DSP1 Preload", NULL, "DSP1 Preloader" }, + + {"DSP RX1 Source", "VMON", "VMON ADC"}, + {"DSP RX1 Source", "IMON", "IMON ADC"}, + {"DSP RX1 Source", "VPMON", "VPMON ADC"}, + {"DSP RX1 Source", "DSPTX1", "DSP1"}, + {"DSP RX1 Source", "DSPTX2", "DSP1"}, + {"DSP RX1 Source", "ASPRX1", "ASPRX1"}, + {"DSP RX1 Source", "ASPRX2", "ASPRX2"}, + {"DSP RX1 Source", "Zero", "ASPRX1"}, + {"DSP1", NULL, "DSP RX1 Source"}, + + {"DSP RX2 Source", "VMON", "VMON ADC"}, + {"DSP RX2 Source", "IMON", "IMON ADC"}, + {"DSP RX2 Source", "VPMON", "VPMON ADC"}, + {"DSP RX2 Source", "DSPTX1", "DSP1"}, + {"DSP RX2 Source", "DSPTX2", "DSP1"}, + {"DSP RX2 Source", "ASPRX1", "ASPRX1"}, + {"DSP RX2 Source", "ASPRX2", "ASPRX2"}, + {"DSP RX2 Source", "Zero", "ASPRX1"}, + {"DSP1", NULL, "DSP RX2 Source"}, + + {"ASP TX1 Source", "VMON", "VMON ADC"}, + {"ASP TX1 Source", "IMON", "IMON ADC"}, + {"ASP TX1 Source", "VPMON", "VPMON ADC"}, + {"ASP TX1 Source", "DSPTX1", "DSP1"}, + {"ASP TX1 Source", "DSPTX2", "DSP1"}, + {"ASP TX1 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX1 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX2 Source", "VMON", "VMON ADC"}, + {"ASP TX2 Source", "IMON", "IMON ADC"}, + {"ASP TX2 Source", "VPMON", "VPMON ADC"}, + {"ASP TX2 Source", "DSPTX1", "DSP1"}, + {"ASP TX2 Source", "DSPTX2", "DSP1"}, + {"ASP TX2 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX2 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX3 Source", "VMON", "VMON ADC"}, + {"ASP TX3 Source", "IMON", "IMON ADC"}, + {"ASP TX3 Source", "VPMON", "VPMON ADC"}, + {"ASP TX3 Source", "DSPTX1", "DSP1"}, + {"ASP TX3 Source", "DSPTX2", "DSP1"}, + {"ASP TX3 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX3 Source", "ASPRX2", "ASPRX2" }, + {"ASP TX4 Source", "VMON", "VMON ADC"}, + {"ASP TX4 Source", "IMON", "IMON ADC"}, + {"ASP TX4 Source", "VPMON", "VPMON ADC"}, + {"ASP TX4 Source", "DSPTX1", "DSP1"}, + {"ASP TX4 Source", "DSPTX2", "DSP1"}, + {"ASP TX4 Source", "ASPRX1", "ASPRX1" }, + {"ASP TX4 Source", "ASPRX2", "ASPRX2" }, + {"ASPTX1", NULL, "ASP TX1 Source"}, + {"ASPTX2", NULL, "ASP TX2 Source"}, + {"ASPTX3", NULL, "ASP TX3 Source"}, + {"ASPTX4", NULL, "ASP TX4 Source"}, + {"AMP Capture", NULL, "ASPTX1"}, + {"AMP Capture", NULL, "ASPTX2"}, + {"AMP Capture", NULL, "ASPTX3"}, + {"AMP Capture", NULL, "ASPTX4"}, + + {"VMON ADC", NULL, "ASPRX1"}, + {"IMON ADC", NULL, "ASPRX1"}, + {"VPMON ADC", NULL, "ASPRX1"}, + {"TEMPMON ADC", NULL, "ASPRX1"}, + {"VBSTMON ADC", NULL, "ASPRX1"}, + + {"DSP1", NULL, "IMON ADC"}, + {"DSP1", NULL, "VMON ADC"}, + {"DSP1", NULL, "VBSTMON ADC"}, + {"DSP1", NULL, "VPMON ADC"}, + {"DSP1", NULL, "TEMPMON ADC"}, + + {"ASPRX1", NULL, "AMP Playback"}, + {"ASPRX2", NULL, "AMP Playback"}, + {"DRE", "Switch", "CLASS H"}, + {"Main AMP", NULL, "CLASS H"}, + {"Main AMP", NULL, "DRE"}, + {"SPK", NULL, "Main AMP"}, + {"Main AMP", NULL, "ASPTX Ref"}, + {"ASPTX Ref", "Ref", "ASPTX1"}, + {"ASPTX Ref", "Ref", "ASPTX2"}, + {"PCM Source", "ASP", "ASPRX1"}, + {"PCM Source", "DSP", "DSP1"}, + {"CLASS H", NULL, "PCM Source"}, + +}; + +static const struct wm_adsp_region cs35l41_dsp1_regions[] = { + { .type = WMFW_HALO_PM_PACKED, .base = CS35L41_DSP1_PMEM_0 }, + { .type = WMFW_HALO_XM_PACKED, .base = CS35L41_DSP1_XMEM_PACK_0 }, + { .type = WMFW_HALO_YM_PACKED, .base = CS35L41_DSP1_YMEM_PACK_0 }, + {. type = WMFW_ADSP2_XM, .base = CS35L41_DSP1_XMEM_UNPACK24_0}, + {. type = WMFW_ADSP2_YM, .base = CS35L41_DSP1_YMEM_UNPACK24_0}, +}; + +static int cs35l41_set_dai_fmt(struct snd_soc_dai *codec_dai, unsigned int fmt) +{ + struct cs35l41_private *cs35l41 = + snd_soc_codec_get_drvdata(codec_dai->codec); + unsigned int asp_fmt, lrclk_fmt, sclk_fmt, slave_mode; + + pr_debug("++++>CSPL: %s, fmt = %d.\n", __func__, fmt); + + switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { + case SND_SOC_DAIFMT_CBM_CFM: + slave_mode = 1; + break; + case SND_SOC_DAIFMT_CBS_CFS: + slave_mode = 0; + break; + default: + dev_warn(cs35l41->dev, "cs35l41_set_dai_fmt: Mixed master mode unsupported\n"); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_SCLK_MSTR_MASK, + slave_mode << CS35L41_SCLK_MSTR_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_LRCLK_MSTR_MASK, + slave_mode << CS35L41_LRCLK_MSTR_SHIFT); + + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_DSP_A: + asp_fmt = 0; + cs35l41->i2s_mode = false; + cs35l41->dspa_mode = true; + break; + case SND_SOC_DAIFMT_I2S: + asp_fmt = 2; + cs35l41->i2s_mode = true; + cs35l41->dspa_mode = false; + break; + default: + dev_warn(cs35l41->dev, "cs35l41_set_dai_fmt: Invalid or unsupported DAI format\n"); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_FMT_MASK, + asp_fmt << CS35L41_ASP_FMT_SHIFT); + + switch (fmt & SND_SOC_DAIFMT_INV_MASK) { + case SND_SOC_DAIFMT_NB_IF: + lrclk_fmt = 1; + sclk_fmt = 0; + break; + case SND_SOC_DAIFMT_IB_NF: + lrclk_fmt = 0; + sclk_fmt = 1; + break; + case SND_SOC_DAIFMT_IB_IF: + lrclk_fmt = 1; + sclk_fmt = 1; + break; + case SND_SOC_DAIFMT_NB_NF: + lrclk_fmt = 0; + sclk_fmt = 0; + break; + default: + dev_warn(cs35l41->dev, "cs35l41_set_dai_fmt: Invalid DAI clock INV\n"); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_LRCLK_INV_MASK, + lrclk_fmt << CS35L41_LRCLK_INV_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_SCLK_INV_MASK, + sclk_fmt << CS35L41_SCLK_INV_SHIFT); + + pr_debug("---->CSPL: %s, fmt = %d.\n", __func__, fmt); + return 0; +} + +struct cs35l41_global_fs_config { + int rate; + int fs_cfg; +}; + +static const struct cs35l41_global_fs_config cs35l41_fs_rates[] = { + { 12000, 0x01 }, + { 24000, 0x02 }, + { 48000, 0x03 }, + { 96000, 0x04 }, + { 192000, 0x05 }, + { 11025, 0x09 }, + { 22050, 0x0A }, + { 44100, 0x0B }, + { 88200, 0x0C }, + { 176400, 0x0D }, + { 8000, 0x11 }, + { 16000, 0x12 }, + { 32000, 0x13 }, +}; + +static int cs35l41_pcm_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(dai->codec); + int i; + unsigned int rate = params_rate(params); + u8 asp_width, asp_wl; + + pr_debug("++++>CSPL: %s.\n", __func__); + for (i = 0; i < ARRAY_SIZE(cs35l41_fs_rates); i++) { + if (rate == cs35l41_fs_rates[i].rate) + break; + } + regmap_update_bits(cs35l41->regmap, CS35L41_GLOBAL_CLK_CTRL, + CS35L41_GLOBAL_FS_MASK, + cs35l41_fs_rates[i].fs_cfg << CS35L41_GLOBAL_FS_SHIFT); + + asp_wl = params_width(params); + asp_width = params_physical_width(params); + + if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_RX_MASK, + asp_width << CS35L41_ASP_WIDTH_RX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_RX_WL, + CS35L41_ASP_RX_WL_MASK, + asp_wl << CS35L41_ASP_RX_WL_SHIFT); + if (cs35l41->i2s_mode || cs35l41->dspa_mode) { + regmap_update_bits(cs35l41->regmap, + CS35L41_SP_FRAME_RX_SLOT, + CS35L41_ASP_RX1_SLOT_MASK, + ((cs35l41->pdata.right_channel) ? 1 : 0) + << CS35L41_ASP_RX1_SLOT_SHIFT); + regmap_update_bits(cs35l41->regmap, + CS35L41_SP_FRAME_RX_SLOT, + CS35L41_ASP_RX2_SLOT_MASK, + ((cs35l41->pdata.right_channel) ? 0 : 1) + << CS35L41_ASP_RX2_SLOT_SHIFT); + } + } else { + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_ASP_WIDTH_TX_MASK, + asp_width << CS35L41_ASP_WIDTH_TX_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_SP_TX_WL, + CS35L41_ASP_TX_WL_MASK, + asp_wl << CS35L41_ASP_TX_WL_SHIFT); + } + + pr_debug("---->CSPL: %s.\n", __func__); + return 0; +} + +static int cs35l41_get_clk_config(int freq) +{ + int i; + + for (i = 0; i < ARRAY_SIZE(cs35l41_pll_sysclk); i++) { + if (cs35l41_pll_sysclk[i].freq == freq) + return cs35l41_pll_sysclk[i].clk_cfg; + } + + return -EINVAL; +} + +#if 0 +static const unsigned int cs35l41_src_rates[] = { + 8000, 12000, 11025, 16000, 22050, 24000, 32000, + 44100, 48000, 88200, 96000, 176400, 192000 +}; + +static const struct snd_pcm_hw_constraint_list cs35l41_constraints = { + .count = ARRAY_SIZE(cs35l41_src_rates), + .list = cs35l41_src_rates, +}; +#endif + +static int cs35l41_pcm_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + + struct snd_soc_codec *codec = dai->codec; + pr_debug("++++>CSPL: %s.\n", __func__); + + cs35l41_set_dai_fmt(dai, SND_SOC_DAIFMT_CBS_CFS|SND_SOC_DAIFMT_I2S); + cs35l41_codec_set_sysclk(codec, 0, 0, 1536000, 0); +#if 0 + if (substream->runtime) + return snd_pcm_hw_constraint_list(substream->runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, &cs35l41_constraints); +#endif + pr_debug("---->CSPL: %s.\n", __func__); + return 0; +} + +static int cs35l41_codec_set_sysclk(struct snd_soc_codec *codec, + int clk_id, int source, unsigned int freq, + int dir) +{ + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + int val = 0; + cs35l41->extclk_freq = freq; + + pr_debug("++++>CSPL: %s: clk_id = %d, src = %d, freq = %d, dir = %d.\n", __func__, clk_id, source, freq, dir); + dev_info(codec->dev, "%s: clk_id=%d, src=%d, freq=%d\n", __func__, clk_id, source, freq); + + switch (clk_id) { + case 0: + cs35l41->clksrc = CS35L41_PLLSRC_SCLK; + break; + case 1: + cs35l41->clksrc = CS35L41_PLLSRC_LRCLK; + break; + case 2: + cs35l41->clksrc = CS35L41_PLLSRC_PDMCLK; + break; + case 3: + cs35l41->clksrc = CS35L41_PLLSRC_SELF; + break; + case 4: + cs35l41->clksrc = CS35L41_PLLSRC_MCLK; + break; + default: + dev_err(codec->dev, "Invalid CLK Config\n"); + return -EINVAL; + } + + cs35l41->extclk_cfg = cs35l41_get_clk_config(freq); + + if (cs35l41->extclk_cfg < 0) { + dev_err(codec->dev, "Invalid CLK Config: %d, freq: %u\n", + cs35l41->extclk_cfg, freq); + return -EINVAL; + } + + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_OPENLOOP_MASK, + 1 << CS35L41_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_REFCLK_FREQ_MASK, + cs35l41->extclk_cfg << CS35L41_REFCLK_FREQ_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_EN_MASK, + 0 << CS35L41_PLL_CLK_EN_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_SEL_MASK, cs35l41->clksrc); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_OPENLOOP_MASK, + 0 << CS35L41_PLL_OPENLOOP_SHIFT); + regmap_update_bits(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, + CS35L41_PLL_CLK_EN_MASK, + 1 << CS35L41_PLL_CLK_EN_SHIFT); + + regmap_read(cs35l41->regmap, CS35L41_PLL_CLK_CTRL, &val); + dev_info(codec->dev, "%s: 0x%x <== 0x%x\n",__func__, CS35L41_PLL_CLK_CTRL, val); + pr_debug("---->CSPL: %s.\n", __func__); + + return 0; +} + +static int cs35l41_dai_set_sysclk(struct snd_soc_dai *dai, + int clk_id, unsigned int freq, int dir) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + pr_debug("++++>CSPL: %s: clk_id=%d, freq=%d, dir=%d\n", __func__, clk_id, freq, dir); + if (cs35l41_get_clk_config(freq) < 0) { + dev_err(codec->dev, "Invalid CLK Config freq: %u\n", freq); + return -EINVAL; + } + + if (clk_id == CS35L41_PLLSRC_SCLK) + cs35l41->sclk = freq; + pr_debug("---->CSPL: %s.\n", __func__); + + return 0; +} + +static int cs35l41_digital_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(cs35l41->dev, "%s: %d\n", __func__, mute); + pr_debug("++++>CSPL: %s, mute = %d.\n", __func__, mute); + + if (mute) { + regmap_update_bits(cs35l41->regmap,0x6000, + 0x7ff << 3, 0x400 << 3 | 0x7); + mdelay(30); + } else { + regmap_update_bits(cs35l41->regmap,0x6000, + 0x7ff << 3, 0x0 << 3 | 0x4 ); + } + + pr_debug("---->CSPL: %s.\n", __func__); + return 0; +} + +static int cs35l41_boost_config(struct cs35l41_private *cs35l41, + int boost_ind, int boost_cap, int boost_ipk) +{ + int ret; + unsigned char bst_lbst_val, bst_cbst_range, bst_ipk_scaled; + struct regmap *regmap = cs35l41->regmap; + struct device *dev = cs35l41->dev; + + switch (boost_ind) { + case 1000: /* 1.0 uH */ + bst_lbst_val = 0; + break; + case 1200: /* 1.2 uH */ + bst_lbst_val = 1; + break; + case 1500: /* 1.5 uH */ + bst_lbst_val = 2; + break; + case 2200: /* 2.2 uH */ + bst_lbst_val = 3; + break; + default: + dev_err(dev, "Invalid boost inductor value: %d nH\n", + boost_ind); + return -EINVAL; + } + + switch (boost_cap) { + case 0 ... 19: + bst_cbst_range = 0; + break; + case 20 ... 50: + bst_cbst_range = 1; + break; + case 51 ... 100: + bst_cbst_range = 2; + break; + case 101 ... 200: + bst_cbst_range = 3; + break; + default: /* 201 uF and greater */ + bst_cbst_range = 4; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, + CS35L41_BST_K1_MASK, + cs35l41_bst_k1_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K1_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost K1 coefficient\n"); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_COEFF, + CS35L41_BST_K2_MASK, + cs35l41_bst_k2_table[bst_lbst_val][bst_cbst_range] + << CS35L41_BST_K2_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost K2 coefficient\n"); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, + CS35L41_BST_SLOPE_MASK, + cs35l41_bst_slope_table[bst_lbst_val] + << CS35L41_BST_SLOPE_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost slope coefficient\n"); + return ret; + } + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_SLOPE_LBST, + CS35L41_BST_LBST_VAL_MASK, + bst_lbst_val << CS35L41_BST_LBST_VAL_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost inductor value\n"); + return ret; + } + + if ((boost_ipk < 1600) || (boost_ipk > 4500)) { + dev_err(dev, "Invalid boost inductor peak current: %d mA\n", + boost_ipk); + return -EINVAL; + } + bst_ipk_scaled = ((boost_ipk - 1600) / 50) + 0x10; + + ret = regmap_update_bits(regmap, CS35L41_BSTCVRT_PEAK_CUR, + CS35L41_BST_IPK_MASK, + bst_ipk_scaled << CS35L41_BST_IPK_SHIFT); + if (ret) { + dev_err(dev, "Failed to write boost inductor peak current\n"); + return ret; + } + + return 0; +} + +static int cs35l41_codec_probe(struct snd_soc_codec *codec) +{ + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct classh_cfg *classh = &cs35l41->pdata.classh_config; + int ret; + + /* Set Platform Data */ + /* Required */ + if (cs35l41->pdata.bst_ipk && + cs35l41->pdata.bst_ind && cs35l41->pdata.bst_cap) { + ret = cs35l41_boost_config(cs35l41, cs35l41->pdata.bst_ind, + cs35l41->pdata.bst_cap, + cs35l41->pdata.bst_ipk); + if (ret) { + dev_err(cs35l41->dev, "Error in Boost DT config\n"); + return ret; + } + } else { + dev_err(cs35l41->dev, "Incomplete Boost component DT config\n"); + return -EINVAL; + } + + /* Optional */ + if (cs35l41->pdata.sclk_frc) + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_SCLK_FRC_MASK, + cs35l41->pdata.sclk_frc << + CS35L41_SCLK_FRC_SHIFT); + + if (cs35l41->pdata.lrclk_frc) + regmap_update_bits(cs35l41->regmap, CS35L41_SP_FORMAT, + CS35L41_LRCLK_FRC_MASK, + cs35l41->pdata.lrclk_frc << + CS35L41_LRCLK_FRC_SHIFT); + + if (cs35l41->pdata.amp_gain_zc) + regmap_update_bits(cs35l41->regmap, CS35L41_AMP_GAIN_CTRL, + CS35L41_AMP_GAIN_ZC_MASK, + cs35l41->pdata.amp_gain_zc << + CS35L41_AMP_GAIN_ZC_SHIFT); + + if (cs35l41->pdata.bst_vctrl) + regmap_update_bits(cs35l41->regmap, CS35L41_BSTCVRT_VCTRL1, + CS35L41_BST_CTL_MASK, cs35l41->pdata.bst_vctrl); + + if (cs35l41->pdata.temp_warn_thld) + regmap_update_bits(cs35l41->regmap, CS35L41_DTEMP_WARN_THLD, + CS35L41_TEMP_THLD_MASK, + cs35l41->pdata.temp_warn_thld); + + if (cs35l41->pdata.dout_hiz <= CS35L41_ASP_DOUT_HIZ_MASK && + cs35l41->pdata.dout_hiz >= 0) + regmap_update_bits(cs35l41->regmap, CS35L41_SP_HIZ_CTRL, + CS35L41_ASP_DOUT_HIZ_MASK, + cs35l41->pdata.dout_hiz); + + if (cs35l41->pdata.ng_enable) { + regmap_update_bits(cs35l41->regmap, + CS35L41_MIXER_NGATE_CH1_CFG, + CS35L41_NG_ENABLE_MASK, + CS35L41_NG_ENABLE_MASK); + regmap_update_bits(cs35l41->regmap, + CS35L41_MIXER_NGATE_CH2_CFG, + CS35L41_NG_ENABLE_MASK, + CS35L41_NG_ENABLE_MASK); + + if (cs35l41->pdata.ng_pcm_thld) { + regmap_update_bits(cs35l41->regmap, + CS35L41_MIXER_NGATE_CH1_CFG, + CS35L41_NG_THLD_MASK, + cs35l41->pdata.ng_pcm_thld); + regmap_update_bits(cs35l41->regmap, + CS35L41_MIXER_NGATE_CH2_CFG, + CS35L41_NG_THLD_MASK, + cs35l41->pdata.ng_pcm_thld); + } + + if (cs35l41->pdata.ng_delay) { + regmap_update_bits(cs35l41->regmap, + CS35L41_MIXER_NGATE_CH1_CFG, + CS35L41_NG_DELAY_MASK, + cs35l41->pdata.ng_delay << + CS35L41_NG_DELAY_SHIFT); + regmap_update_bits(cs35l41->regmap, + CS35L41_MIXER_NGATE_CH2_CFG, + CS35L41_NG_DELAY_MASK, + cs35l41->pdata.ng_delay << + CS35L41_NG_DELAY_SHIFT); + } + } + + if (classh->classh_algo_enable) { + if (classh->classh_bst_override) + regmap_update_bits(cs35l41->regmap, + CS35L41_BSTCVRT_VCTRL2, + CS35L41_BST_CTL_SEL_MASK, + CS35L41_BST_CTL_SEL_REG); + if (classh->classh_bst_max_limit) + regmap_update_bits(cs35l41->regmap, + CS35L41_BSTCVRT_VCTRL2, + CS35L41_BST_LIM_MASK, + classh->classh_bst_max_limit << + CS35L41_BST_LIM_SHIFT); + if (classh->classh_mem_depth) + regmap_update_bits(cs35l41->regmap, + CS35L41_CLASSH_CFG, + CS35L41_CH_MEM_DEPTH_MASK, + classh->classh_mem_depth << + CS35L41_CH_MEM_DEPTH_SHIFT); + if (classh->classh_headroom) + regmap_update_bits(cs35l41->regmap, + CS35L41_CLASSH_CFG, + CS35L41_CH_HDRM_CTL_MASK, + classh->classh_headroom << + CS35L41_CH_HDRM_CTL_SHIFT); + if (classh->classh_release_rate) + regmap_update_bits(cs35l41->regmap, + CS35L41_CLASSH_CFG, + CS35L41_CH_REL_RATE_MASK, + classh->classh_release_rate << + CS35L41_CH_REL_RATE_SHIFT); + if (classh->classh_wk_fet_delay) + regmap_update_bits(cs35l41->regmap, + CS35L41_WKFET_CFG, + CS35L41_CH_WKFET_DLY_MASK, + classh->classh_wk_fet_delay << + CS35L41_CH_WKFET_DLY_SHIFT); + if (classh->classh_wk_fet_thld) + regmap_update_bits(cs35l41->regmap, + CS35L41_WKFET_CFG, + CS35L41_CH_WKFET_THLD_MASK, + classh->classh_wk_fet_thld << + CS35L41_CH_WKFET_THLD_SHIFT); + } + + wm_adsp2_codec_probe(&cs35l41->dsp, codec); + + snd_soc_dapm_ignore_suspend(dapm, "AMP Playback"); + snd_soc_dapm_ignore_suspend(dapm, "AMP Capture"); + snd_soc_dapm_ignore_suspend(dapm, "Main AMP"); + snd_soc_dapm_ignore_suspend(dapm, "SPK"); + snd_soc_dapm_ignore_suspend(dapm, "VP"); + snd_soc_dapm_ignore_suspend(dapm, "VBST"); + snd_soc_dapm_ignore_suspend(dapm, "ISENSE"); + snd_soc_dapm_ignore_suspend(dapm, "VSENSE"); + snd_soc_dapm_ignore_suspend(dapm, "TEMP"); + snd_soc_dapm_ignore_suspend(dapm, "DSP1 Preloader"); + snd_soc_dapm_ignore_suspend(dapm, "DSP1 Preload"); + + return 0; +} + +static int cs35l41_irq_gpio_config(struct cs35l41_private *cs35l41) +{ + struct irq_cfg *irq_gpio_cfg1 = &cs35l41->pdata.irq_config1; + struct irq_cfg *irq_gpio_cfg2 = &cs35l41->pdata.irq_config2; + int irq_pol = IRQF_TRIGGER_NONE; + + if (irq_gpio_cfg1->is_present) { + if (irq_gpio_cfg1->irq_pol_inv) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO1_CTRL1, + CS35L41_GPIO_POL_MASK, + CS35L41_GPIO_POL_MASK); + if (irq_gpio_cfg1->irq_out_en) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO1_CTRL1, + CS35L41_GPIO_DIR_MASK, + 0); + if (irq_gpio_cfg1->irq_src_sel) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO_PAD_CONTROL, + CS35L41_GPIO1_CTRL_MASK, + irq_gpio_cfg1->irq_src_sel << + CS35L41_GPIO1_CTRL_SHIFT); + } + + if (irq_gpio_cfg2->is_present) { + if (irq_gpio_cfg2->irq_pol_inv) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO2_CTRL1, + CS35L41_GPIO_POL_MASK, + CS35L41_GPIO_POL_MASK); + if (irq_gpio_cfg2->irq_out_en) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO2_CTRL1, + CS35L41_GPIO_DIR_MASK, + 0); + if (irq_gpio_cfg2->irq_src_sel) + regmap_update_bits(cs35l41->regmap, + CS35L41_GPIO_PAD_CONTROL, + CS35L41_GPIO2_CTRL_MASK, + irq_gpio_cfg2->irq_src_sel << + CS35L41_GPIO2_CTRL_SHIFT); + } + + if (irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_ACTV_LO | CS35L41_VALID_PDATA)) + irq_pol = IRQF_TRIGGER_LOW; + else if (irq_gpio_cfg2->irq_src_sel == + (CS35L41_GPIO_CTRL_ACTV_HI | CS35L41_VALID_PDATA)) + irq_pol = IRQF_TRIGGER_HIGH; + + return irq_pol; +} + +static int cs35l41_codec_remove(struct snd_soc_codec *codec) +{ + struct cs35l41_private *cs35l41 = snd_soc_codec_get_drvdata(codec); + + wm_adsp2_codec_remove(&cs35l41->dsp, codec); + return 0; +} + +static const struct snd_soc_dai_ops cs35l41_ops = { + .startup = cs35l41_pcm_startup, + .set_fmt = cs35l41_set_dai_fmt, + .hw_params = cs35l41_pcm_hw_params, + .set_sysclk = cs35l41_dai_set_sysclk, + .digital_mute = cs35l41_digital_mute, +}; + +static struct snd_soc_dai_driver cs35l41_dai[] = { + { + .name = "cs35l41-pcm", + .id = 0, + .playback = { + .stream_name = "AMP Playback", + .channels_min = 1, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L41_RX_FORMATS, + }, + .capture = { + .stream_name = "AMP Capture", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_KNOT, + .formats = CS35L41_TX_FORMATS, + }, + .ops = &cs35l41_ops, + .symmetric_rates = 1, + }, +}; + + + +static struct snd_soc_codec_driver soc_codec_dev_cs35l41 = { + .probe = cs35l41_codec_probe, + .remove = cs35l41_codec_remove, + .component_driver = { + .dapm_widgets = cs35l41_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(cs35l41_dapm_widgets), + .dapm_routes = cs35l41_audio_map, + .num_dapm_routes = ARRAY_SIZE(cs35l41_audio_map), + .controls = cs35l41_aud_controls, + .num_controls = ARRAY_SIZE(cs35l41_aud_controls), + }, + .set_sysclk = cs35l41_codec_set_sysclk, + .ignore_pmdown_time = false, + .idle_bias_off = true, +}; + +int spk_id_get(struct device_node *np) +{ + int id; + int state; + + state = spk_id_get_pin_3state(np); + if (state < 0) { + pr_err("%s: Can not get id pin state, %d\n", __func__, state); + return VENDOR_ID_NONE; + } + + switch (state) { + case PIN_PULL_DOWN: + id = VENDOR_ID_AAC; + break; + case PIN_PULL_UP: + id = VENDOR_ID_UNKNOWN; + break; + case PIN_FLOAT: + id = VENDOR_ID_GOER; + break; + default: + id = VENDOR_ID_UNKNOWN; + break; + } + return id; +} + +static int cs35l41_handle_of_data(struct device *dev, + struct cs35l41_platform_data *pdata) +{ + struct device_node *np = dev->of_node; + unsigned int val; + int ret; + struct device_node *sub_node; + struct classh_cfg *classh_config = &pdata->classh_config; + struct irq_cfg *irq_gpio1_config = &pdata->irq_config1; + struct irq_cfg *irq_gpio2_config = &pdata->irq_config2; + + if (!np) + return 0; + + pdata->right_channel = of_property_read_bool(np, + "cirrus,right-channel-amp"); + pdata->sclk_frc = of_property_read_bool(np, + "cirrus,sclk-force-output"); + pdata->lrclk_frc = of_property_read_bool(np, + "cirrus,lrclk-force-output"); + pdata->amp_gain_zc = of_property_read_bool(np, + "cirrus,amp-gain-zc"); + + if (of_property_read_u32(np, "cirrus,temp-warn_threshold", &val) >= 0) + pdata->temp_warn_thld = val | CS35L41_VALID_PDATA; + + ret = of_property_read_u32(np, "cirrus,boost-ctl-millivolt", &val); + if (ret >= 0) { + if (val < 2550 || val > 11000) { + dev_err(dev, + "Invalid Boost Voltage %u mV\n", val); + return -EINVAL; + } + pdata->bst_vctrl = ((val - 2550) / 100) + 1; + } + + ret = of_property_read_u32(np, "cirrus,boost-peak-milliamp", &val); + if (ret >= 0) + pdata->bst_ipk = val; + + ret = of_property_read_u32(np, "cirrus,boost-ind-nanohenry", &val); + if (ret >= 0) + pdata->bst_ind = val; + + ret = of_property_read_u32(np, "cirrus,boost-cap-microfarad", &val); + if (ret >= 0) + pdata->bst_cap = val; + + ret = of_property_read_u32(np, "cirrus,asp-sdout-hiz", &val); + if (ret >= 0) + pdata->dout_hiz = val; + else + pdata->dout_hiz = -1; + + pdata->ng_enable = of_property_read_bool(np, + "cirrus,noise-gate-enable"); + if (of_property_read_u32(np, "cirrus,noise-gate-threshold", &val) >= 0) + pdata->ng_pcm_thld = val | CS35L41_VALID_PDATA; + if (of_property_read_u32(np, "cirrus,noise-gate-delay", &val) >= 0) + pdata->ng_delay = val | CS35L41_VALID_PDATA; + + pdata->spk_id_gpio_p = of_parse_phandle(np, + "cirrus,spk-id-pin", 0); + if (!pdata->spk_id_gpio_p) { + dev_err(dev, "property %s not detected in node %s", + "cirrus,spk-id-pin", np->full_name); + pdata->mnSpkType = VENDOR_ID_NONE; + } else { + pdata->mnSpkType = spk_id_get(pdata->spk_id_gpio_p); + } + dev_info(dev, "spk is is %d", pdata->mnSpkType); + + sub_node = of_get_child_by_name(np, "cirrus,classh-internal-algo"); + classh_config->classh_algo_enable = sub_node ? true : false; + + if (classh_config->classh_algo_enable) { + classh_config->classh_bst_override = + of_property_read_bool(sub_node, + "cirrus,classh-bst-overide"); + + ret = of_property_read_u32(sub_node, + "cirrus,classh-bst-max-limit", + &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + classh_config->classh_bst_max_limit = val; + } + + ret = of_property_read_u32(sub_node, "cirrus,classh-mem-depth", + &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + classh_config->classh_mem_depth = val; + } + + ret = of_property_read_u32(sub_node, + "cirrus,classh-release-rate", &val); + if (ret >= 0) + classh_config->classh_release_rate = val; + + ret = of_property_read_u32(sub_node, "cirrus,classh-headroom", + &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + classh_config->classh_headroom = val; + } + + ret = of_property_read_u32(sub_node, + "cirrus,classh-wk-fet-delay", &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + classh_config->classh_wk_fet_delay = val; + } + + ret = of_property_read_u32(sub_node, + "cirrus,classh-wk-fet-thld", &val); + if (ret >= 0) + classh_config->classh_wk_fet_thld = val; + } + of_node_put(sub_node); + + /* GPIO1 Pin Config */ + sub_node = of_get_child_by_name(np, "cirrus,gpio-config1"); + irq_gpio1_config->is_present = sub_node ? true : false; + if (irq_gpio1_config->is_present) { + irq_gpio1_config->irq_pol_inv = of_property_read_bool(sub_node, + "cirrus,gpio-polarity-invert"); + irq_gpio1_config->irq_out_en = of_property_read_bool(sub_node, + "cirrus,gpio-output-enable"); + ret = of_property_read_u32(sub_node, "cirrus,gpio-src-select", + &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + irq_gpio1_config->irq_src_sel = val; + } + } + of_node_put(sub_node); + + /* GPIO2 Pin Config */ + sub_node = of_get_child_by_name(np, "cirrus,gpio-config2"); + irq_gpio2_config->is_present = sub_node ? true : false; + if (irq_gpio2_config->is_present) { + irq_gpio2_config->irq_pol_inv = of_property_read_bool(sub_node, + "cirrus,gpio-polarity-invert"); + irq_gpio2_config->irq_out_en = of_property_read_bool(sub_node, + "cirrus,gpio-output-enable"); + ret = of_property_read_u32(sub_node, "cirrus,gpio-src-select", + &val); + if (ret >= 0) { + val |= CS35L41_VALID_PDATA; + irq_gpio2_config->irq_src_sel = val; + } + } + of_node_put(sub_node); + + return 0; +} + +static const struct reg_sequence cs35l41_reva0_errata_patch[] = { + {0x00000040, 0x00005555}, + {0x00000040, 0x0000AAAA}, + {0x00003854, 0x05180240}, + {CS35L41_VIMON_SPKMON_RESYNC, 0x00000000}, + {CS35L41_OTP_TRIM_30, 0x9091A1C8}, + {0x00003014, 0x0200EE0E}, + {CS35L41_BSTCVRT_DCM_CTRL, 0x00000051}, + {0x00000054, 0x00000004}, + {CS35L41_IRQ1_DB3, 0x00000000}, + {CS35L41_IRQ2_DB3, 0x00000000}, + {CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000}, + {CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000}, + {CS35L41_ASP_CONTROL4, 0x00000000}, + {0x00000040, 0x0000CCCC}, + {0x00000040, 0x00003333}, +}; + +static const struct reg_sequence cs35l41_revb0_errata_patch[] = { + {0x00000040, 0x00005555}, + {0x00000040, 0x0000AAAA}, + {CS35L41_VIMON_SPKMON_RESYNC, 0x00000000}, + {CS35L41_BSTCVRT_DCM_CTRL, 0x00000051}, + {CS35L41_DSP1_YM_ACCEL_PL0_PRI, 0x00000000}, + {CS35L41_DSP1_XM_ACCEL_PL0_PRI, 0x00000000}, + {CS35L41_ASP_CONTROL4, 0x00000000}, + {0x00000040, 0x0000CCCC}, + {0x00000040, 0x00003333}, +}; + +static int cs35l41_dsp_init(struct cs35l41_private *cs35l41) +{ + struct wm_adsp *dsp; + int ret; + + dsp = &cs35l41->dsp; + dsp->part = "cs35l41"; + dsp->num = 1; + dsp->type = WMFW_HALO; + dsp->rev = 0; + dsp->dev = cs35l41->dev; + dsp->regmap = cs35l41->regmap; + + dsp->base = CS35L41_DSP1_CTRL_BASE; + dsp->base_sysinfo = CS35L41_DSP1_SYS_ID; + dsp->mem = cs35l41_dsp1_regions; + dsp->num_mems = ARRAY_SIZE(cs35l41_dsp1_regions); + dsp->unlock_all = true; + + dsp->n_rx_rates = CS35L41_DSP_N_RX_RATES; + dsp->n_tx_rates = CS35L41_DSP_N_TX_RATES; + ret = wm_halo_init(dsp); + cs35l41->halo_booted = false; + + regmap_write(cs35l41->regmap, CS35L41_DSP1_RX5_SRC, + CS35L41_INPUT_SRC_VPMON); + regmap_write(cs35l41->regmap, CS35L41_DSP1_RX6_SRC, + CS35L41_INPUT_SRC_CLASSH); + regmap_write(cs35l41->regmap, CS35L41_DSP1_RX7_SRC, + CS35L41_INPUT_SRC_TEMPMON); + regmap_write(cs35l41->regmap, CS35L41_DSP1_RX8_SRC, + CS35L41_INPUT_SRC_RSVD); + + return ret; +} + +int cs35l41_probe(struct cs35l41_private *cs35l41, + struct cs35l41_platform_data *pdata) +{ + int ret; + u32 regid, reg_revid, i, mtl_revid, int_status, chipid_match; + int timeout = 100; + int irq_pol = 0; + + dev_info(cs35l41->dev, "cs35l41 proble\n" ); + + /* Default to RESUME cmd */ + cs35l41->cspl_cmd = (unsigned int)CSPL_MBOX_CMD_RESUME; + + for (i = 0; i < ARRAY_SIZE(cs35l41_supplies); i++) + cs35l41->supplies[i].supply = cs35l41_supplies[i]; + + cs35l41->num_supplies = ARRAY_SIZE(cs35l41_supplies); + + ret = devm_regulator_bulk_get(cs35l41->dev, cs35l41->num_supplies, + cs35l41->supplies); + if (ret != 0) { + dev_err(cs35l41->dev, + "Failed to request core supplies: %d\n", + ret); + return ret; + } + + if (pdata) { + cs35l41->pdata = *pdata; + } else if (cs35l41->dev->of_node) { + ret = cs35l41_handle_of_data(cs35l41->dev, &cs35l41->pdata); + if (ret != 0) + return ret; + } else { + ret = -EINVAL; + goto err; + } + + ret = regulator_bulk_enable(cs35l41->num_supplies, cs35l41->supplies); + if (ret != 0) { + dev_err(cs35l41->dev, + "Failed to enable core supplies: %d\n", ret); + return ret; + } + + /* returning NULL can be an option if in stereo mode */ + cs35l41->reset_gpio = of_get_named_gpio(cs35l41->dev->of_node, + "cs,cdc-reset-gpio", 0); + + dev_err(cs35l41->dev, "Set GPIO %d as RESET pin\n", cs35l41->reset_gpio); + if (!gpio_is_valid(cs35l41->reset_gpio)) { + dev_err(cs35l41->dev, "GPIO %d is invalid!\n", cs35l41->reset_gpio); + } + + if (cs35l41->reset_gpio) { + dev_err(cs35l41->dev, "Reset cs35l41\n"); + /* satisfy minimum reset pulse width spec */ + usleep_range(2000, 2100); + + gpio_direction_output(cs35l41->reset_gpio, 0); + msleep(5); + gpio_direction_output(cs35l41->reset_gpio, 1); + msleep(2); + } + + usleep_range(2000, 2100); + + do { + if (timeout == 0) { + dev_err(cs35l41->dev, + "Timeout waiting for OTP_BOOT_DONE\n"); + ret = -EBUSY; + goto err; + } + usleep_range(1000, 1100); + regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS4, &int_status); + timeout--; + } while (!(int_status & CS35L41_OTP_BOOT_DONE)); + + regmap_read(cs35l41->regmap, CS35L41_IRQ1_STATUS3, &int_status); + if (int_status & CS35L41_OTP_BOOT_ERR) { + dev_err(cs35l41->dev, "OTP Boot error\n"); + ret = -EINVAL; + goto err; + } + + ret = regmap_read(cs35l41->regmap, CS35L41_DEVID, ®id); + if (ret < 0) { + dev_err(cs35l41->dev, "Get Device ID failed\n"); + goto err; + } + + ret = regmap_read(cs35l41->regmap, CS35L41_REVID, ®_revid); + if (ret < 0) { + dev_err(cs35l41->dev, "Get Revision ID failed\n"); + goto err; + } + + mtl_revid = reg_revid & CS35L41_MTLREVID_MASK; + + /* CS35L41 will have even MTLREVID + * CS35L41R will have odd MTLREVID + */ + chipid_match = (mtl_revid % 2) ? CS35L41R_CHIP_ID : CS35L41_CHIP_ID; + if (regid != chipid_match) { + dev_err(cs35l41->dev, "CS35L41 Device ID (%X). Expected ID %X\n", + regid, chipid_match); + ret = -ENODEV; + goto err; + } + + irq_pol = cs35l41_irq_gpio_config(cs35l41); + + init_completion(&cs35l41->global_pdn_done); + init_completion(&cs35l41->global_pup_done); + + init_completion(&cs35l41->mbox_cmd); + + ret = devm_request_threaded_irq(cs35l41->dev, cs35l41->irq, NULL, + cs35l41_irq, irq_pol | IRQF_ONESHOT, + "cs35l41", cs35l41); + + /* CS35L41 needs INT for PDN_DONE */ + if (ret != 0) { + dev_err(cs35l41->dev, "Failed to request IRQ: %d\n", cs35l41->irq); + //goto err; + } + + /* Set interrupt masks for critical errors */ + regmap_write(cs35l41->regmap, CS35L41_IRQ1_MASK1, + CS35L41_INT1_MASK_DEFAULT); + + switch (reg_revid) { + case CS35L41_REVID_A0: + ret = regmap_multi_reg_write(cs35l41->regmap, + cs35l41_reva0_errata_patch, + ARRAY_SIZE(cs35l41_reva0_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply A0 errata patch %d\n", ret); + goto err; + } + break; + case CS35L41_REVID_B0: + ret = regmap_multi_reg_write(cs35l41->regmap, + cs35l41_revb0_errata_patch, + ARRAY_SIZE(cs35l41_revb0_errata_patch)); + if (ret < 0) { + dev_err(cs35l41->dev, + "Failed to apply B0 errata patch %d\n", ret); + goto err; + } + break; + } + + ret = cs35l41_otp_unpack(cs35l41); + if (ret < 0) { + dev_err(cs35l41->dev, "OTP Unpack failed\n"); + goto err; + } + + cs35l41_dsp_init(cs35l41); + + ret = snd_soc_register_codec(cs35l41->dev, &soc_codec_dev_cs35l41, + cs35l41_dai, ARRAY_SIZE(cs35l41_dai)); + if (ret < 0) { + dev_err(cs35l41->dev, "%s: Register codec failed\n", __func__); + goto err; + } + + dev_info(cs35l41->dev, "Cirrus Logic CS35L41 (%x), Revision: %02X\n", + regid, reg_revid); + +err: + regulator_bulk_disable(cs35l41->num_supplies, cs35l41->supplies); + return ret; +} + +MODULE_DESCRIPTION("ASoC CS35L41 driver"); +MODULE_AUTHOR("David Rhodes, Cirrus Logic Inc, "); +MODULE_LICENSE("GPL"); diff --git a/techpack/audio/asoc/codecs/cs35l41/cs35l41.h b/techpack/audio/asoc/codecs/cs35l41/cs35l41.h new file mode 100644 index 000000000000..4569abf5f1d6 --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/cs35l41.h @@ -0,0 +1,764 @@ +/* + * cs35l41.h -- CS35L41 ALSA SoC audio driver + * + * Copyright 2018 Cirrus Logic, Inc. + * + * Author: Brian Austin + * David Rhodes + * + * 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. + * + */ + +#ifndef __CS35L41_H__ +#define __CS35L41_H__ + +#include + +#define CS35L41_FIRSTREG 0x00000000 +#define CS35L41_LASTREG 0x03804FE8 +#define CS35L41_DEVID 0x00000000 +#define CS35L41_REVID 0x00000004 +#define CS35L41_FABID 0x00000008 +#define CS35L41_RELID 0x0000000C +#define CS35L41_OTPID 0x00000010 +#define CS35L41_SFT_RESET 0x00000020 +#define CS35L41_TEST_KEY_CTL 0x00000040 +#define CS35L41_USER_KEY_CTL 0x00000044 +#define CS35L41_OTP_MEM0 0x00000400 +#define CS35L41_OTP_MEM31 0x0000047C +#define CS35L41_OTP_CTRL0 0x00000500 +#define CS35L41_OTP_CTRL1 0x00000504 +#define CS35L41_OTP_CTRL3 0x00000508 +#define CS35L41_OTP_CTRL4 0x0000050C +#define CS35L41_OTP_CTRL5 0x00000510 +#define CS35L41_OTP_CTRL6 0x00000514 +#define CS35L41_OTP_CTRL7 0x00000518 +#define CS35L41_OTP_CTRL8 0x0000051C +#define CS35L41_PWR_CTRL1 0x00002014 +#define CS35L41_PWR_CTRL2 0x00002018 +#define CS35L41_PWR_CTRL3 0x0000201C +#define CS35L41_CTRL_OVRRIDE 0x00002020 +#define CS35L41_AMP_OUT_MUTE 0x00002024 +#define CS35L41_PROTECT_REL_ERR_IGN 0x00002034 +#define CS35L41_GPIO_PAD_CONTROL 0x0000242C +#define CS35L41_JTAG_CONTROL 0x00002438 +#define CS35L41_PLL_CLK_CTRL 0x00002C04 +#define CS35L41_DSP_CLK_CTRL 0x00002C08 +#define CS35L41_GLOBAL_CLK_CTRL 0x00002C0C +#define CS35L41_DATA_FS_SEL 0x00002C10 +#define CS35L41_MDSYNC_EN 0x00003400 +#define CS35L41_MDSYNC_TX_ID 0x00003408 +#define CS35L41_MDSYNC_PWR_CTRL 0x0000340C +#define CS35L41_MDSYNC_DATA_TX 0x00003410 +#define CS35L41_MDSYNC_TX_STATUS 0x00003414 +#define CS35L41_MDSYNC_DATA_RX 0x0000341C +#define CS35L41_MDSYNC_RX_STATUS 0x00003420 +#define CS35L41_MDSYNC_ERR_STATUS 0x00003424 +#define CS35L41_MDSYNC_SYNC_PTE2 0x00003528 +#define CS35L41_MDSYNC_SYNC_PTE3 0x0000352C +#define CS35L41_MDSYNC_SYNC_MSM_STATUS 0x0000353C +#define CS35L41_BSTCVRT_VCTRL1 0x00003800 +#define CS35L41_BSTCVRT_VCTRL2 0x00003804 +#define CS35L41_BSTCVRT_PEAK_CUR 0x00003808 +#define CS35L41_BSTCVRT_SFT_RAMP 0x0000380C +#define CS35L41_BSTCVRT_COEFF 0x00003810 +#define CS35L41_BSTCVRT_SLOPE_LBST 0x00003814 +#define CS35L41_BSTCVRT_SW_FREQ 0x00003818 +#define CS35L41_BSTCVRT_DCM_CTRL 0x0000381C +#define CS35L41_BSTCVRT_DCM_MODE_FORCE 0x00003820 +#define CS35L41_BSTCVRT_OVERVOLT_CTRL 0x00003830 +#define CS35L41_VI_VOL_POL 0x00004000 +#define CS35L41_VIMON_SPKMON_RESYNC 0x00004100 +#define CS35L41_DTEMP_WARN_THLD 0x00004220 +#define CS35L41_DTEMP_CFG 0x00004224 +#define CS35L41_DTEMP_EN 0x00004308 +#define CS35L41_VPVBST_FS_SEL 0x00004400 +#define CS35L41_SP_ENABLES 0x00004800 +#define CS35L41_SP_RATE_CTRL 0x00004804 +#define CS35L41_SP_FORMAT 0x00004808 +#define CS35L41_SP_HIZ_CTRL 0x0000480C +#define CS35L41_SP_FRAME_TX_SLOT 0x00004810 +#define CS35L41_SP_FRAME_RX_SLOT 0x00004820 +#define CS35L41_SP_TX_WL 0x00004830 +#define CS35L41_SP_RX_WL 0x00004840 +#define CS35L41_ASP_CONTROL4 0x00004854 +#define CS35L41_DAC_PCM1_SRC 0x00004C00 +#define CS35L41_ASP_TX1_SRC 0x00004C20 +#define CS35L41_ASP_TX2_SRC 0x00004C24 +#define CS35L41_ASP_TX3_SRC 0x00004C28 +#define CS35L41_ASP_TX4_SRC 0x00004C2C +#define CS35L41_DSP1_RX1_SRC 0x00004C40 +#define CS35L41_DSP1_RX2_SRC 0x00004C44 +#define CS35L41_DSP1_RX3_SRC 0x00004C48 +#define CS35L41_DSP1_RX4_SRC 0x00004C4C +#define CS35L41_DSP1_RX5_SRC 0x00004C50 +#define CS35L41_DSP1_RX6_SRC 0x00004C54 +#define CS35L41_DSP1_RX7_SRC 0x00004C58 +#define CS35L41_DSP1_RX8_SRC 0x00004C5C +#define CS35L41_NGATE1_SRC 0x00004C60 +#define CS35L41_NGATE2_SRC 0x00004C64 +#define CS35L41_AMP_DIG_VOL_CTRL 0x00006000 +#define CS35L41_VPBR_CFG 0x00006404 +#define CS35L41_VBBR_CFG 0x00006408 +#define CS35L41_VPBR_STATUS 0x0000640C +#define CS35L41_VBBR_STATUS 0x00006410 +#define CS35L41_OVERTEMP_CFG 0x00006414 +#define CS35L41_AMP_ERR_VOL 0x00006418 +#define CS35L41_VOL_STATUS_TO_DSP 0x00006450 +#define CS35L41_CLASSH_CFG 0x00006800 +#define CS35L41_WKFET_CFG 0x00006804 +#define CS35L41_NG_CFG 0x00006808 +#define CS35L41_AMP_GAIN_CTRL 0x00006C04 +#define CS35L41_DAC_MSM_CFG 0x00007400 +#define CS35L41_IRQ1_CFG 0x00010000 +#define CS35L41_IRQ1_STATUS 0x00010004 +#define CS35L41_IRQ1_STATUS1 0x00010010 +#define CS35L41_IRQ1_STATUS2 0x00010014 +#define CS35L41_IRQ1_STATUS3 0x00010018 +#define CS35L41_IRQ1_STATUS4 0x0001001C +#define CS35L41_IRQ1_RAW_STATUS1 0x00010090 +#define CS35L41_IRQ1_RAW_STATUS2 0x00010094 +#define CS35L41_IRQ1_RAW_STATUS3 0x00010098 +#define CS35L41_IRQ1_RAW_STATUS4 0x0001009C +#define CS35L41_IRQ1_MASK1 0x00010110 +#define CS35L41_IRQ1_MASK2 0x00010114 +#define CS35L41_IRQ1_MASK3 0x00010118 +#define CS35L41_IRQ1_MASK4 0x0001011C +#define CS35L41_IRQ1_FRC1 0x00010190 +#define CS35L41_IRQ1_FRC2 0x00010194 +#define CS35L41_IRQ1_FRC3 0x00010198 +#define CS35L41_IRQ1_FRC4 0x0001019C +#define CS35L41_IRQ1_EDGE1 0x00010210 +#define CS35L41_IRQ1_EDGE4 0x0001021C +#define CS35L41_IRQ1_POL1 0x00010290 +#define CS35L41_IRQ1_POL2 0x00010294 +#define CS35L41_IRQ1_POL3 0x00010298 +#define CS35L41_IRQ1_POL4 0x0001029C +#define CS35L41_IRQ1_DB3 0x00010318 +#define CS35L41_IRQ2_CFG 0x00010800 +#define CS35L41_IRQ2_STATUS 0x00010804 +#define CS35L41_IRQ2_STATUS1 0x00010810 +#define CS35L41_IRQ2_STATUS2 0x00010814 +#define CS35L41_IRQ2_STATUS3 0x00010818 +#define CS35L41_IRQ2_STATUS4 0x0001081C +#define CS35L41_IRQ2_RAW_STATUS1 0x00010890 +#define CS35L41_IRQ2_RAW_STATUS2 0x00010894 +#define CS35L41_IRQ2_RAW_STATUS3 0x00010898 +#define CS35L41_IRQ2_RAW_STATUS4 0x0001089C +#define CS35L41_IRQ2_MASK1 0x00010910 +#define CS35L41_IRQ2_MASK2 0x00010914 +#define CS35L41_IRQ2_MASK3 0x00010918 +#define CS35L41_IRQ2_MASK4 0x0001091C +#define CS35L41_IRQ2_FRC1 0x00010990 +#define CS35L41_IRQ2_FRC2 0x00010994 +#define CS35L41_IRQ2_FRC3 0x00010998 +#define CS35L41_IRQ2_FRC4 0x0001099C +#define CS35L41_IRQ2_EDGE1 0x00010A10 +#define CS35L41_IRQ2_EDGE4 0x00010A1C +#define CS35L41_IRQ2_POL1 0x00010A90 +#define CS35L41_IRQ2_POL2 0x00010A94 +#define CS35L41_IRQ2_POL3 0x00010A98 +#define CS35L41_IRQ2_POL4 0x00010A9C +#define CS35L41_IRQ2_DB3 0x00010B18 +#define CS35L41_GPIO_STATUS1 0x00011000 +#define CS35L41_GPIO1_CTRL1 0x00011008 +#define CS35L41_GPIO2_CTRL1 0x0001100C +#define CS35L41_MIXER_NGATE_CFG 0x00012000 +#define CS35L41_MIXER_NGATE_CH1_CFG 0x00012004 +#define CS35L41_MIXER_NGATE_CH2_CFG 0x00012008 +#define CS35L41_DSP_MBOX_1 0x00013000 +#define CS35L41_DSP_MBOX_2 0x00013004 +#define CS35L41_DSP_MBOX_3 0x00013008 +#define CS35L41_DSP_MBOX_4 0x0001300C +#define CS35L41_DSP_MBOX_5 0x00013010 +#define CS35L41_DSP_MBOX_6 0x00013014 +#define CS35L41_DSP_MBOX_7 0x00013018 +#define CS35L41_DSP_MBOX_8 0x0001301C +#define CS35L41_DSP_VIRT1_MBOX_1 0x00013020 +#define CS35L41_DSP_VIRT1_MBOX_2 0x00013024 +#define CS35L41_DSP_VIRT1_MBOX_3 0x00013028 +#define CS35L41_DSP_VIRT1_MBOX_4 0x0001302C +#define CS35L41_DSP_VIRT1_MBOX_5 0x00013030 +#define CS35L41_DSP_VIRT1_MBOX_6 0x00013034 +#define CS35L41_DSP_VIRT1_MBOX_7 0x00013038 +#define CS35L41_DSP_VIRT1_MBOX_8 0x0001303C +#define CS35L41_DSP_VIRT2_MBOX_1 0x00013040 +#define CS35L41_DSP_VIRT2_MBOX_2 0x00013044 +#define CS35L41_DSP_VIRT2_MBOX_3 0x00013048 +#define CS35L41_DSP_VIRT2_MBOX_4 0x0001304C +#define CS35L41_DSP_VIRT2_MBOX_5 0x00013050 +#define CS35L41_DSP_VIRT2_MBOX_6 0x00013054 +#define CS35L41_DSP_VIRT2_MBOX_7 0x00013058 +#define CS35L41_DSP_VIRT2_MBOX_8 0x0001305C +#define CS35L41_CLOCK_DETECT_1 0x00014000 +#define CS35L41_TIMER1_CONTROL 0x00015000 +#define CS35L41_TIMER1_COUNT_PRESET 0x00015004 +#define CS35L41_TIMER1_START_STOP 0x0001500C +#define CS35L41_TIMER1_STATUS 0x00015010 +#define CS35L41_TIMER1_COUNT_READBACK 0x00015014 +#define CS35L41_TIMER1_DSP_CLK_CFG 0x00015018 +#define CS35L41_TIMER1_DSP_CLK_STATUS 0x0001501C +#define CS35L41_TIMER2_CONTROL 0x00015100 +#define CS35L41_TIMER2_COUNT_PRESET 0x00015104 +#define CS35L41_TIMER2_START_STOP 0x0001510C +#define CS35L41_TIMER2_STATUS 0x00015110 +#define CS35L41_TIMER2_COUNT_READBACK 0x00015114 +#define CS35L41_TIMER2_DSP_CLK_CFG 0x00015118 +#define CS35L41_TIMER2_DSP_CLK_STATUS 0x0001511C +#define CS35L41_DFT_JTAG_CONTROL 0x00016000 +#define CS35L41_DIE_STS1 0x00017040 +#define CS35L41_DIE_STS2 0x00017044 +#define CS35L41_TEMP_CAL1 0x00017048 +#define CS35L41_TEMP_CAL2 0x0001704C +#define CS35L41_DSP1_XMEM_PACK_0 0x02000000 +#define CS35L41_DSP1_XMEM_PACK_3068 0x02002FF0 +#define CS35L41_DSP1_XMEM_UNPACK32_0 0x02400000 +#define CS35L41_DSP1_XMEM_UNPACK32_2046 0x02401FF8 +#define CS35L41_DSP1_TIMESTAMP_COUNT 0x025C0800 +#define CS35L41_DSP1_SYS_ID 0x025E0000 +#define CS35L41_DSP1_SYS_VERSION 0x025E0004 +#define CS35L41_DSP1_SYS_CORE_ID 0x025E0008 +#define CS35L41_DSP1_SYS_AHB_ADDR 0x025E000C +#define CS35L41_DSP1_SYS_XSRAM_SIZE 0x025E0010 +#define CS35L41_DSP1_SYS_YSRAM_SIZE 0x025E0018 +#define CS35L41_DSP1_SYS_PSRAM_SIZE 0x025E0020 +#define CS35L41_DSP1_SYS_PM_BOOT_SIZE 0x025E0028 +#define CS35L41_DSP1_SYS_FEATURES 0x025E002C +#define CS35L41_DSP1_SYS_FIR_FILTERS 0x025E0030 +#define CS35L41_DSP1_SYS_LMS_FILTERS 0x025E0034 +#define CS35L41_DSP1_SYS_XM_BANK_SIZE 0x025E0038 +#define CS35L41_DSP1_SYS_YM_BANK_SIZE 0x025E003C +#define CS35L41_DSP1_SYS_PM_BANK_SIZE 0x025E0040 +#define CS35L41_DSP1_AHBM_WIN0_CTRL0 0x025E2000 +#define CS35L41_DSP1_AHBM_WIN0_CTRL1 0x025E2004 +#define CS35L41_DSP1_AHBM_WIN1_CTRL0 0x025E2008 +#define CS35L41_DSP1_AHBM_WIN1_CTRL1 0x025E200C +#define CS35L41_DSP1_AHBM_WIN2_CTRL0 0x025E2010 +#define CS35L41_DSP1_AHBM_WIN2_CTRL1 0x025E2014 +#define CS35L41_DSP1_AHBM_WIN3_CTRL0 0x025E2018 +#define CS35L41_DSP1_AHBM_WIN3_CTRL1 0x025E201C +#define CS35L41_DSP1_AHBM_WIN4_CTRL0 0x025E2020 +#define CS35L41_DSP1_AHBM_WIN4_CTRL1 0x025E2024 +#define CS35L41_DSP1_AHBM_WIN5_CTRL0 0x025E2028 +#define CS35L41_DSP1_AHBM_WIN5_CTRL1 0x025E202C +#define CS35L41_DSP1_AHBM_WIN6_CTRL0 0x025E2030 +#define CS35L41_DSP1_AHBM_WIN6_CTRL1 0x025E2034 +#define CS35L41_DSP1_AHBM_WIN7_CTRL0 0x025E2038 +#define CS35L41_DSP1_AHBM_WIN7_CTRL1 0x025E203C +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL0 0x025E2040 +#define CS35L41_DSP1_AHBM_WIN_DBG_CTRL1 0x025E2044 +#define CS35L41_DSP1_XMEM_UNPACK24_0 0x02800000 +#define CS35L41_DSP1_XMEM_UNPACK24_4093 0x02803FF4 +#define CS35L41_DSP1_CTRL_BASE 0x02B80000 +#define CS35L41_DSP1_CORE_SOFT_RESET 0x02B80010 +#define CS35L41_DSP1_DEBUG 0x02B80040 +#define CS35L41_DSP1_TIMER_CTRL 0x02B80048 +#define CS35L41_DSP1_STREAM_ARB_CTRL 0x02B80050 +#define CS35L41_DSP1_RX1_RATE 0x02B80080 +#define CS35L41_DSP1_RX2_RATE 0x02B80088 +#define CS35L41_DSP1_RX3_RATE 0x02B80090 +#define CS35L41_DSP1_RX4_RATE 0x02B80098 +#define CS35L41_DSP1_RX5_RATE 0x02B800A0 +#define CS35L41_DSP1_RX6_RATE 0x02B800A8 +#define CS35L41_DSP1_RX7_RATE 0x02B800B0 +#define CS35L41_DSP1_RX8_RATE 0x02B800B8 +#define CS35L41_DSP1_TX1_RATE 0x02B80280 +#define CS35L41_DSP1_TX2_RATE 0x02B80288 +#define CS35L41_DSP1_TX3_RATE 0x02B80290 +#define CS35L41_DSP1_TX4_RATE 0x02B80298 +#define CS35L41_DSP1_TX5_RATE 0x02B802A0 +#define CS35L41_DSP1_TX6_RATE 0x02B802A8 +#define CS35L41_DSP1_TX7_RATE 0x02B802B0 +#define CS35L41_DSP1_TX8_RATE 0x02B802B8 +#define CS35L41_DSP1_NMI_CTRL1 0x02B80480 +#define CS35L41_DSP1_NMI_CTRL2 0x02B80488 +#define CS35L41_DSP1_NMI_CTRL3 0x02B80490 +#define CS35L41_DSP1_NMI_CTRL4 0x02B80498 +#define CS35L41_DSP1_NMI_CTRL5 0x02B804A0 +#define CS35L41_DSP1_NMI_CTRL6 0x02B804A8 +#define CS35L41_DSP1_NMI_CTRL7 0x02B804B0 +#define CS35L41_DSP1_NMI_CTRL8 0x02B804B8 +#define CS35L41_DSP1_RESUME_CTRL 0x02B80500 +#define CS35L41_DSP1_IRQ1_CTRL 0x02B80508 +#define CS35L41_DSP1_IRQ2_CTRL 0x02B80510 +#define CS35L41_DSP1_IRQ3_CTRL 0x02B80518 +#define CS35L41_DSP1_IRQ4_CTRL 0x02B80520 +#define CS35L41_DSP1_IRQ5_CTRL 0x02B80528 +#define CS35L41_DSP1_IRQ6_CTRL 0x02B80530 +#define CS35L41_DSP1_IRQ7_CTRL 0x02B80538 +#define CS35L41_DSP1_IRQ8_CTRL 0x02B80540 +#define CS35L41_DSP1_IRQ9_CTRL 0x02B80548 +#define CS35L41_DSP1_IRQ10_CTRL 0x02B80550 +#define CS35L41_DSP1_IRQ11_CTRL 0x02B80558 +#define CS35L41_DSP1_IRQ12_CTRL 0x02B80560 +#define CS35L41_DSP1_IRQ13_CTRL 0x02B80568 +#define CS35L41_DSP1_IRQ14_CTRL 0x02B80570 +#define CS35L41_DSP1_IRQ15_CTRL 0x02B80578 +#define CS35L41_DSP1_IRQ16_CTRL 0x02B80580 +#define CS35L41_DSP1_IRQ17_CTRL 0x02B80588 +#define CS35L41_DSP1_IRQ18_CTRL 0x02B80590 +#define CS35L41_DSP1_IRQ19_CTRL 0x02B80598 +#define CS35L41_DSP1_IRQ20_CTRL 0x02B805A0 +#define CS35L41_DSP1_IRQ21_CTRL 0x02B805A8 +#define CS35L41_DSP1_IRQ22_CTRL 0x02B805B0 +#define CS35L41_DSP1_IRQ23_CTRL 0x02B805B8 +#define CS35L41_DSP1_SCRATCH1 0x02B805C0 +#define CS35L41_DSP1_SCRATCH2 0x02B805C8 +#define CS35L41_DSP1_SCRATCH3 0x02B805D0 +#define CS35L41_DSP1_SCRATCH4 0x02B805D8 +#define CS35L41_DSP1_CCM_CORE_CTRL 0x02BC1000 +#define CS35L41_DSP1_CCM_CLK_OVERRIDE 0x02BC1008 +#define CS35L41_DSP1_XM_MSTR_EN 0x02BC2000 +#define CS35L41_DSP1_XM_CORE_PRI 0x02BC2008 +#define CS35L41_DSP1_XM_AHB_PACK_PL_PRI 0x02BC2010 +#define CS35L41_DSP1_XM_AHB_UP_PL_PRI 0x02BC2018 +#define CS35L41_DSP1_XM_ACCEL_PL0_PRI 0x02BC2020 +#define CS35L41_DSP1_XM_NPL0_PRI 0x02BC2078 +#define CS35L41_DSP1_YM_MSTR_EN 0x02BC20C0 +#define CS35L41_DSP1_YM_CORE_PRI 0x02BC20C8 +#define CS35L41_DSP1_YM_AHB_PACK_PL_PRI 0x02BC20D0 +#define CS35L41_DSP1_YM_AHB_UP_PL_PRI 0x02BC20D8 +#define CS35L41_DSP1_YM_ACCEL_PL0_PRI 0x02BC20E0 +#define CS35L41_DSP1_YM_NPL0_PRI 0x02BC2138 +#define CS35L41_DSP1_PM_MSTR_EN 0x02BC2180 +#define CS35L41_DSP1_PM_PATCH0_ADDR 0x02BC2188 +#define CS35L41_DSP1_PM_PATCH0_EN 0x02BC218C +#define CS35L41_DSP1_PM_PATCH0_DATA_LO 0x02BC2190 +#define CS35L41_DSP1_PM_PATCH0_DATA_HI 0x02BC2194 +#define CS35L41_DSP1_PM_PATCH1_ADDR 0x02BC2198 +#define CS35L41_DSP1_PM_PATCH1_EN 0x02BC219C +#define CS35L41_DSP1_PM_PATCH1_DATA_LO 0x02BC21A0 +#define CS35L41_DSP1_PM_PATCH1_DATA_HI 0x02BC21A4 +#define CS35L41_DSP1_PM_PATCH2_ADDR 0x02BC21A8 +#define CS35L41_DSP1_PM_PATCH2_EN 0x02BC21AC +#define CS35L41_DSP1_PM_PATCH2_DATA_LO 0x02BC21B0 +#define CS35L41_DSP1_PM_PATCH2_DATA_HI 0x02BC21B4 +#define CS35L41_DSP1_PM_PATCH3_ADDR 0x02BC21B8 +#define CS35L41_DSP1_PM_PATCH3_EN 0x02BC21BC +#define CS35L41_DSP1_PM_PATCH3_DATA_LO 0x02BC21C0 +#define CS35L41_DSP1_PM_PATCH3_DATA_HI 0x02BC21C4 +#define CS35L41_DSP1_PM_PATCH4_ADDR 0x02BC21C8 +#define CS35L41_DSP1_PM_PATCH4_EN 0x02BC21CC +#define CS35L41_DSP1_PM_PATCH4_DATA_LO 0x02BC21D0 +#define CS35L41_DSP1_PM_PATCH4_DATA_HI 0x02BC21D4 +#define CS35L41_DSP1_PM_PATCH5_ADDR 0x02BC21D8 +#define CS35L41_DSP1_PM_PATCH5_EN 0x02BC21DC +#define CS35L41_DSP1_PM_PATCH5_DATA_LO 0x02BC21E0 +#define CS35L41_DSP1_PM_PATCH5_DATA_HI 0x02BC21E4 +#define CS35L41_DSP1_PM_PATCH6_ADDR 0x02BC21E8 +#define CS35L41_DSP1_PM_PATCH6_EN 0x02BC21EC +#define CS35L41_DSP1_PM_PATCH6_DATA_LO 0x02BC21F0 +#define CS35L41_DSP1_PM_PATCH6_DATA_HI 0x02BC21F4 +#define CS35L41_DSP1_PM_PATCH7_ADDR 0x02BC21F8 +#define CS35L41_DSP1_PM_PATCH7_EN 0x02BC21FC +#define CS35L41_DSP1_PM_PATCH7_DATA_LO 0x02BC2200 +#define CS35L41_DSP1_PM_PATCH7_DATA_HI 0x02BC2204 +#define CS35L41_DSP1_MPU_XM_ACCESS0 0x02BC3000 +#define CS35L41_DSP1_MPU_YM_ACCESS0 0x02BC3004 +#define CS35L41_DSP1_MPU_WNDW_ACCESS0 0x02BC3008 +#define CS35L41_DSP1_MPU_XREG_ACCESS0 0x02BC300C +#define CS35L41_DSP1_MPU_YREG_ACCESS0 0x02BC3014 +#define CS35L41_DSP1_MPU_XM_ACCESS1 0x02BC3018 +#define CS35L41_DSP1_MPU_YM_ACCESS1 0x02BC301C +#define CS35L41_DSP1_MPU_WNDW_ACCESS1 0x02BC3020 +#define CS35L41_DSP1_MPU_XREG_ACCESS1 0x02BC3024 +#define CS35L41_DSP1_MPU_YREG_ACCESS1 0x02BC302C +#define CS35L41_DSP1_MPU_XM_ACCESS2 0x02BC3030 +#define CS35L41_DSP1_MPU_YM_ACCESS2 0x02BC3034 +#define CS35L41_DSP1_MPU_WNDW_ACCESS2 0x02BC3038 +#define CS35L41_DSP1_MPU_XREG_ACCESS2 0x02BC303C +#define CS35L41_DSP1_MPU_YREG_ACCESS2 0x02BC3044 +#define CS35L41_DSP1_MPU_XM_ACCESS3 0x02BC3048 +#define CS35L41_DSP1_MPU_YM_ACCESS3 0x02BC304C +#define CS35L41_DSP1_MPU_WNDW_ACCESS3 0x02BC3050 +#define CS35L41_DSP1_MPU_XREG_ACCESS3 0x02BC3054 +#define CS35L41_DSP1_MPU_YREG_ACCESS3 0x02BC305C +#define CS35L41_DSP1_MPU_XM_VIO_ADDR 0x02BC3100 +#define CS35L41_DSP1_MPU_XM_VIO_STATUS 0x02BC3104 +#define CS35L41_DSP1_MPU_YM_VIO_ADDR 0x02BC3108 +#define CS35L41_DSP1_MPU_YM_VIO_STATUS 0x02BC310C +#define CS35L41_DSP1_MPU_PM_VIO_ADDR 0x02BC3110 +#define CS35L41_DSP1_MPU_PM_VIO_STATUS 0x02BC3114 +#define CS35L41_DSP1_MPU_LOCK_CONFIG 0x02BC3140 +#define CS35L41_DSP1_MPU_WDT_RST_CTRL 0x02BC3180 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG0 0x02BC5000 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG1 0x02BC5004 +#define CS35L41_DSP1_STRMARB_MSTR0_CFG2 0x02BC5008 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG0 0x02BC5010 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG1 0x02BC5014 +#define CS35L41_DSP1_STRMARB_MSTR1_CFG2 0x02BC5018 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG0 0x02BC5020 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG1 0x02BC5024 +#define CS35L41_DSP1_STRMARB_MSTR2_CFG2 0x02BC5028 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG0 0x02BC5030 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG1 0x02BC5034 +#define CS35L41_DSP1_STRMARB_MSTR3_CFG2 0x02BC5038 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG0 0x02BC5040 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG1 0x02BC5044 +#define CS35L41_DSP1_STRMARB_MSTR4_CFG2 0x02BC5048 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG0 0x02BC5050 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG1 0x02BC5054 +#define CS35L41_DSP1_STRMARB_MSTR5_CFG2 0x02BC5058 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG0 0x02BC5060 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG1 0x02BC5064 +#define CS35L41_DSP1_STRMARB_MSTR6_CFG2 0x02BC5068 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG0 0x02BC5070 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG1 0x02BC5074 +#define CS35L41_DSP1_STRMARB_MSTR7_CFG2 0x02BC5078 +#define CS35L41_DSP1_STRMARB_TX0_CFG0 0x02BC5200 +#define CS35L41_DSP1_STRMARB_TX0_CFG1 0x02BC5204 +#define CS35L41_DSP1_STRMARB_TX1_CFG0 0x02BC5208 +#define CS35L41_DSP1_STRMARB_TX1_CFG1 0x02BC520C +#define CS35L41_DSP1_STRMARB_TX2_CFG0 0x02BC5210 +#define CS35L41_DSP1_STRMARB_TX2_CFG1 0x02BC5214 +#define CS35L41_DSP1_STRMARB_TX3_CFG0 0x02BC5218 +#define CS35L41_DSP1_STRMARB_TX3_CFG1 0x02BC521C +#define CS35L41_DSP1_STRMARB_TX4_CFG0 0x02BC5220 +#define CS35L41_DSP1_STRMARB_TX4_CFG1 0x02BC5224 +#define CS35L41_DSP1_STRMARB_TX5_CFG0 0x02BC5228 +#define CS35L41_DSP1_STRMARB_TX5_CFG1 0x02BC522C +#define CS35L41_DSP1_STRMARB_TX6_CFG0 0x02BC5230 +#define CS35L41_DSP1_STRMARB_TX6_CFG1 0x02BC5234 +#define CS35L41_DSP1_STRMARB_TX7_CFG0 0x02BC5238 +#define CS35L41_DSP1_STRMARB_TX7_CFG1 0x02BC523C +#define CS35L41_DSP1_STRMARB_RX0_CFG0 0x02BC5400 +#define CS35L41_DSP1_STRMARB_RX0_CFG1 0x02BC5404 +#define CS35L41_DSP1_STRMARB_RX1_CFG0 0x02BC5408 +#define CS35L41_DSP1_STRMARB_RX1_CFG1 0x02BC540C +#define CS35L41_DSP1_STRMARB_RX2_CFG0 0x02BC5410 +#define CS35L41_DSP1_STRMARB_RX2_CFG1 0x02BC5414 +#define CS35L41_DSP1_STRMARB_RX3_CFG0 0x02BC5418 +#define CS35L41_DSP1_STRMARB_RX3_CFG1 0x02BC541C +#define CS35L41_DSP1_STRMARB_RX4_CFG0 0x02BC5420 +#define CS35L41_DSP1_STRMARB_RX4_CFG1 0x02BC5424 +#define CS35L41_DSP1_STRMARB_RX5_CFG0 0x02BC5428 +#define CS35L41_DSP1_STRMARB_RX5_CFG1 0x02BC542C +#define CS35L41_DSP1_STRMARB_RX6_CFG0 0x02BC5430 +#define CS35L41_DSP1_STRMARB_RX6_CFG1 0x02BC5434 +#define CS35L41_DSP1_STRMARB_RX7_CFG0 0x02BC5438 +#define CS35L41_DSP1_STRMARB_RX7_CFG1 0x02BC543C +#define CS35L41_DSP1_STRMARB_IRQ0_CFG0 0x02BC5600 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG1 0x02BC5604 +#define CS35L41_DSP1_STRMARB_IRQ0_CFG2 0x02BC5608 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG0 0x02BC5610 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG1 0x02BC5614 +#define CS35L41_DSP1_STRMARB_IRQ1_CFG2 0x02BC5618 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG0 0x02BC5620 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG1 0x02BC5624 +#define CS35L41_DSP1_STRMARB_IRQ2_CFG2 0x02BC5628 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG0 0x02BC5630 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG1 0x02BC5634 +#define CS35L41_DSP1_STRMARB_IRQ3_CFG2 0x02BC5638 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG0 0x02BC5640 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG1 0x02BC5644 +#define CS35L41_DSP1_STRMARB_IRQ4_CFG2 0x02BC5648 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG0 0x02BC5650 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG1 0x02BC5654 +#define CS35L41_DSP1_STRMARB_IRQ5_CFG2 0x02BC5658 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG0 0x02BC5660 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG1 0x02BC5664 +#define CS35L41_DSP1_STRMARB_IRQ6_CFG2 0x02BC5668 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG0 0x02BC5670 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG1 0x02BC5674 +#define CS35L41_DSP1_STRMARB_IRQ7_CFG2 0x02BC5678 +#define CS35L41_DSP1_STRMARB_RESYNC_MSK 0x02BC5A00 +#define CS35L41_DSP1_STRMARB_ERR_STATUS 0x02BC5A08 +#define CS35L41_DSP1_INTPCTL_RES_STATIC 0x02BC6000 +#define CS35L41_DSP1_INTPCTL_RES_DYN 0x02BC6004 +#define CS35L41_DSP1_INTPCTL_NMI_CTRL 0x02BC6008 +#define CS35L41_DSP1_INTPCTL_IRQ_INV 0x02BC6010 +#define CS35L41_DSP1_INTPCTL_IRQ_MODE 0x02BC6014 +#define CS35L41_DSP1_INTPCTL_IRQ_EN 0x02BC6018 +#define CS35L41_DSP1_INTPCTL_IRQ_MSK 0x02BC601C +#define CS35L41_DSP1_INTPCTL_IRQ_FLUSH 0x02BC6020 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKCLR 0x02BC6024 +#define CS35L41_DSP1_INTPCTL_IRQ_FRC 0x02BC6028 +#define CS35L41_DSP1_INTPCTL_IRQ_MSKSET 0x02BC602C +#define CS35L41_DSP1_INTPCTL_IRQ_ERR 0x02BC6030 +#define CS35L41_DSP1_INTPCTL_IRQ_PEND 0x02BC6034 +#define CS35L41_DSP1_INTPCTL_IRQ_GEN 0x02BC6038 +#define CS35L41_DSP1_INTPCTL_TESTBITS 0x02BC6040 +#define CS35L41_DSP1_WDT_CONTROL 0x02BC7000 +#define CS35L41_DSP1_WDT_STATUS 0x02BC7008 +#define CS35L41_DSP1_YMEM_PACK_0 0x02C00000 +#define CS35L41_DSP1_YMEM_PACK_1532 0x02C017F0 +#define CS35L41_DSP1_YMEM_UNPACK32_0 0x03000000 +#define CS35L41_DSP1_YMEM_UNPACK32_1022 0x03000FF8 +#define CS35L41_DSP1_YMEM_UNPACK24_0 0x03400000 +#define CS35L41_DSP1_YMEM_UNPACK24_2045 0x03401FF4 +#define CS35L41_DSP1_PMEM_0 0x03800000 +#define CS35L41_DSP1_PMEM_5114 0x03804FE8 + +/*test regs for emulation bringup*/ +#define CS35L41_PLL_OVR 0x00003018 +#define CS35L41_BST_TEST_DUTY 0x00003900 +#define CS35L41_DIGPWM_IOCTRL 0x0000706C + +/*registers populated by OTP*/ +#define CS35L41_OTP_TRIM_1 0x0000208c +#define CS35L41_OTP_TRIM_2 0x00002090 +#define CS35L41_OTP_TRIM_3 0x00003010 +#define CS35L41_OTP_TRIM_4 0x0000300C +#define CS35L41_OTP_TRIM_5 0x0000394C +#define CS35L41_OTP_TRIM_6 0x00003950 +#define CS35L41_OTP_TRIM_7 0x00003954 +#define CS35L41_OTP_TRIM_8 0x00003958 +#define CS35L41_OTP_TRIM_9 0x0000395C +#define CS35L41_OTP_TRIM_10 0x0000416C +#define CS35L41_OTP_TRIM_11 0x00004160 +#define CS35L41_OTP_TRIM_12 0x00004170 +#define CS35L41_OTP_TRIM_13 0x00004360 +#define CS35L41_OTP_TRIM_14 0x00004448 +#define CS35L41_OTP_TRIM_15 0x0000444C +#define CS35L41_OTP_TRIM_16 0x00006E30 +#define CS35L41_OTP_TRIM_17 0x00006E34 +#define CS35L41_OTP_TRIM_18 0x00006E38 +#define CS35L41_OTP_TRIM_19 0x00006E3C +#define CS35L41_OTP_TRIM_20 0x00006E40 +#define CS35L41_OTP_TRIM_21 0x00006E44 +#define CS35L41_OTP_TRIM_22 0x00006E48 +#define CS35L41_OTP_TRIM_23 0x00006E4C +#define CS35L41_OTP_TRIM_24 0x00006E50 +#define CS35L41_OTP_TRIM_25 0x00006E54 +#define CS35L41_OTP_TRIM_26 0x00006E58 +#define CS35L41_OTP_TRIM_27 0x00006E5C +#define CS35L41_OTP_TRIM_28 0x00006E60 +#define CS35L41_OTP_TRIM_29 0x00006E64 +#define CS35L41_OTP_TRIM_30 0x00007418 +#define CS35L41_OTP_TRIM_31 0x0000741C +#define CS35L41_OTP_TRIM_32 0x00007434 +#define CS35L41_OTP_TRIM_33 0x00007068 +#define CS35L41_OTP_TRIM_34 0x0000410C +#define CS35L41_OTP_TRIM_35 0x0000400C +#define CS35L41_OTP_TRIM_36 0x00002030 + +#define CS35L41_MAX_CACHE_REG 0x0000006B +#define CS35L41_OTP_SIZE_WORDS 32 +#define CS35L41_NUM_OTP_ELEM 100 +#define CS35L41_NUM_OTP_MAPS 3 + +#define CS35L41_VALID_PDATA 0x80000000 + +#define CS35L41_SCLK_MSTR_MASK 0x10 +#define CS35L41_SCLK_MSTR_SHIFT 4 +#define CS35L41_LRCLK_MSTR_MASK 0x01 +#define CS35L41_LRCLK_MSTR_SHIFT 0 +#define CS35L41_SCLK_INV_MASK 0x40 +#define CS35L41_SCLK_INV_SHIFT 6 +#define CS35L41_LRCLK_INV_MASK 0x04 +#define CS35L41_LRCLK_INV_SHIFT 2 +#define CS35L41_SCLK_FRC_MASK 0x20 +#define CS35L41_SCLK_FRC_SHIFT 5 +#define CS35L41_LRCLK_FRC_MASK 0x02 +#define CS35L41_LRCLK_FRC_SHIFT 1 + +#define CS35L41_AMP_GAIN_ZC_MASK 0x0400 +#define CS35L41_AMP_GAIN_ZC_SHIFT 10 + +#define CS35L41_BST_CTL_MASK 0xFF +#define CS35L41_BST_CTL_SEL_MASK 0x03 +#define CS35L41_BST_CTL_SEL_REG 0x00 +#define CS35L41_BST_CTL_SEL_CLASSH 0x01 +#define CS35L41_BST_IPK_MASK 0x7F +#define CS35L41_BST_IPK_SHIFT 0 +#define CS35L41_BST_LIM_MASK 0x4 +#define CS35L41_BST_LIM_SHIFT 2 +#define CS35L41_BST_K1_MASK 0x000000FF +#define CS35L41_BST_K1_SHIFT 0 +#define CS35L41_BST_K2_MASK 0x0000FF00 +#define CS35L41_BST_K2_SHIFT 8 +#define CS35L41_BST_SLOPE_MASK 0x0000FF00 +#define CS35L41_BST_SLOPE_SHIFT 8 +#define CS35L41_BST_LBST_VAL_MASK 0x00000003 +#define CS35L41_BST_LBST_VAL_SHIFT 0 + +#define CS35L41_TEMP_THLD_MASK 0x03 +#define CS35L41_VMON_IMON_VOL_MASK 0x07FF07FF +#define CS35L41_PDM_MODE_MASK 0x01 +#define CS35L41_PDM_MODE_SHIFT 0 + +#define CS35L41_CH_MEM_DEPTH_MASK 0x07 +#define CS35L41_CH_MEM_DEPTH_SHIFT 0 +#define CS35L41_CH_HDRM_CTL_MASK 0x007F0000 +#define CS35L41_CH_HDRM_CTL_SHIFT 16 +#define CS35L41_CH_REL_RATE_MASK 0xFF00 +#define CS35L41_CH_REL_RATE_SHIFT 8 +#define CS35L41_CH_WKFET_DLY_MASK 0x001C +#define CS35L41_CH_WKFET_DLY_SHIFT 2 +#define CS35L41_CH_WKFET_THLD_MASK 0x0F00 +#define CS35L41_CH_WKFET_THLD_SHIFT 8 + +#define CS35L41_NG_ENABLE_MASK 0x00010000 +#define CS35L41_NG_ENABLE_SHIFT 16 +#define CS35L41_NG_THLD_MASK 0x7 +#define CS35L41_NG_THLD_SHIFT 0 +#define CS35L41_NG_DELAY_MASK 0x0F00 +#define CS35L41_NG_DELAY_SHIFT 8 + +#define CS35L41_ASP_FMT_MASK 0x0700 +#define CS35L41_ASP_FMT_SHIFT 8 +#define CS35L41_ASP_DOUT_HIZ_MASK 0x03 +#define CS35L41_ASP_DOUT_HIZ_SHIFT 0 +#define CS35L41_ASP_WIDTH_16 0x10 +#define CS35L41_ASP_WIDTH_24 0x18 +#define CS35L41_ASP_WIDTH_32 0x20 +#define CS35L41_ASP_WIDTH_TX_MASK 0xFF0000 +#define CS35L41_ASP_WIDTH_TX_SHIFT 16 +#define CS35L41_ASP_WIDTH_RX_MASK 0xFF000000 +#define CS35L41_ASP_WIDTH_RX_SHIFT 24 +#define CS35L41_ASP_RX1_SLOT_MASK 0x3F +#define CS35L41_ASP_RX1_SLOT_SHIFT 0 +#define CS35L41_ASP_RX2_SLOT_MASK 0x3F00 +#define CS35L41_ASP_RX2_SLOT_SHIFT 8 +#define CS35L41_ASP_RX_WL_MASK 0x3F +#define CS35L41_ASP_TX_WL_MASK 0x3F +#define CS35L41_ASP_RX_WL_SHIFT 0 +#define CS35L41_ASP_TX_WL_SHIFT 0 +#define CS35L41_ASP_SOURCE_MASK 0x7F + +#define CS35L41_INPUT_SRC_ASPRX1 0x08 +#define CS35L41_INPUT_SRC_ASPRX2 0x09 +#define CS35L41_INPUT_SRC_VMON 0x18 +#define CS35L41_INPUT_SRC_IMON 0x19 +#define CS35L41_INPUT_SRC_CLASSH 0x21 +#define CS35L41_INPUT_SRC_VPMON 0x28 +#define CS35L41_INPUT_SRC_VBSTMON 0x29 +#define CS35L41_INPUT_SRC_TEMPMON 0x3A +#define CS35L41_INPUT_SRC_RSVD 0x3B +#define CS35L41_INPUT_DSP_TX1 0x32 +#define CS35L41_INPUT_DSP_TX2 0x33 + +#define CS35L41_PLL_CLK_SEL_MASK 0x07 +#define CS35L41_PLL_CLK_SEL_SHIFT 0 +#define CS35L41_PLL_CLK_EN_MASK 0x10 +#define CS35L41_PLL_CLK_EN_SHIFT 4 +#define CS35L41_PLL_OPENLOOP_MASK 0x0800 +#define CS35L41_PLL_OPENLOOP_SHIFT 11 +#define CS35L41_PLLSRC_SCLK 0 +#define CS35L41_PLLSRC_LRCLK 1 +#define CS35L41_PLLSRC_SELF 3 +#define CS35L41_PLLSRC_PDMCLK 4 +#define CS35L41_PLLSRC_MCLK 5 +#define CS35L41_PLLSRC_SWIRE 7 +#define CS35L41_REFCLK_FREQ_MASK 0x7E0 +#define CS35L41_REFCLK_FREQ_SHIFT 5 + +#define CS35L41_GLOBAL_FS_MASK 0x1F +#define CS35L41_GLOBAL_FS_SHIFT 0 + +#define CS35L41_GLOBAL_EN_MASK 0x01 +#define CS35L41_GLOBAL_EN_SHIFT 0 +#define CS35L41_BST_EN_MASK 0x0030 +#define CS35L41_BST_EN_SHIFT 4 +#define CS35L41_BST_EN_DEFAULT 0x2 + +#define CS35L41_PDN_DONE_MASK 0x00800000 +#define CS35L41_PDN_DONE_SHIFT 23 +#define CS35L41_PUP_DONE_MASK 0x01000000 +#define CS35L41_PUP_DONE_SHIFT 24 + +#define CS35L36_PUP_DONE_IRQ_UNMASK 0x5F +#define CS35L36_PUP_DONE_IRQ_MASK 0xBF + +#define CS35L41_AMP_SHORT_ERR 0x80000000 +#define CS35L41_BST_SHORT_ERR 0x0100 +#define CS35L41_TEMP_WARN 0x8000 +#define CS35L41_TEMP_ERR 0x00020000 +#define CS35L41_BST_OVP_ERR 0x40 +#define CS35L41_BST_DCM_UVP_ERR 0x80 +#define CS35L41_OTP_BOOT_DONE 0x02 +#define CS35L41_PLL_UNLOCK 0x10 +#define CS35L41_OTP_BOOT_ERR 0x80000000 + +#define CS35L41_AMP_SHORT_ERR_RLS 0x02 +#define CS35L41_BST_SHORT_ERR_RLS 0x04 +#define CS35L41_BST_OVP_ERR_RLS 0x08 +#define CS35L41_BST_UVP_ERR_RLS 0x10 +#define CS35L41_TEMP_WARN_ERR_RLS 0x20 +#define CS35L41_TEMP_ERR_RLS 0x40 + +#define CS35L41_INT1_MASK_DEFAULT 0x7FFCFE3F +#define CS35L41_INT1_UNMASK_PUP 0xFEFFFFFF +#define CS35L41_INT1_UNMASK_PDN 0xFF7FFFFF + +#define CS35L41_GPIO_DIR_MASK 0x80000000 +#define CS35L41_GPIO1_CTRL_MASK 0x00030000 +#define CS35L41_GPIO1_CTRL_SHIFT 16 +#define CS35L41_GPIO2_CTRL_MASK 0x07000000 +#define CS35L41_GPIO2_CTRL_SHIFT 24 +#define CS35L41_GPIO_CTRL_ACTV_LO 4 +#define CS35L41_GPIO_CTRL_ACTV_HI 5 +#define CS35L41_GPIO_POL_MASK 0x1000 +#define CS35L41_GPIO_POL_SHIFT 12 + +#define CS35L41_CHIP_ID 0x35a40 +#define CS35L41R_CHIP_ID 0x35b40 +#define CS35L41_MTLREVID_MASK 0x0F +#define CS35L41_REVID_A0 0xA0 +#define CS35L41_REVID_B0 0xB0 + +#define CS35L41_DSP_N_RX_RATES 8 +#define CS35L41_DSP_N_TX_RATES 8 +#define CS35L41_HALO_CORE_RESET 0x00000200 + +#define CS35L41_SPI_MAX_FREQ_OTP 4000000 + +#define CS35L41_RX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE) +#define CS35L41_TX_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE \ + | SNDRV_PCM_FMTBIT_S32_LE) + +bool cs35l41_readable_reg(struct device *dev, unsigned int reg); +bool cs35l41_precious_reg(struct device *dev, unsigned int reg); +bool cs35l41_volatile_reg(struct device *dev, unsigned int reg); + +struct cs35l41_otp_packed_element_t { + u32 reg; + u8 shift; + u8 size; +}; + +struct cs35l41_otp_map_element_t { + u32 id; + u32 num_elements; + const struct cs35l41_otp_packed_element_t *map; + u32 bit_offset; + u32 word_offset; +}; + +extern const struct reg_default cs35l41_reg[CS35L41_MAX_CACHE_REG]; +extern const struct cs35l41_otp_map_element_t + cs35l41_otp_map_map[CS35L41_NUM_OTP_MAPS]; + +#define CS35L41_REGSTRIDE 4 +#define CS35L41_MBOXWAIT 100 + +#define CS35L41_DSP_VIRT1_MBOX_SHIFT 20 +#define CS35L41_DSP_VIRT2_MBOX_SHIFT 21 +#define CS35L41_CSPL_MBOX_STS CS35L41_DSP_MBOX_2 +/* Firmware update following reg */ +#define CS35L41_CSPL_MBOX_CMD_FW CS35L41_DSP_VIRT2_MBOX_1 +#define CS35L41_CSPL_MBOX_CMD_FW_SHIFT CS35L41_DSP_VIRT2_MBOX_SHIFT +/* Driver update following reg */ +#define CS35L41_CSPL_MBOX_CMD_DRV CS35L41_DSP_VIRT1_MBOX_1 +#define CS35L41_CSPL_MBOX_CMD_DRV_SHIFT CS35L41_DSP_VIRT1_MBOX_SHIFT + +enum cs35l41_cspl_mboxstate { + CSPL_MBOX_STS_RUNNING = 0, + CSPL_MBOX_STS_PAUSED = 1, + CSPL_MBOX_STS_RDY_FOR_REINIT = 2, +}; + +enum cs35l41_cspl_mboxcmd { + CSPL_MBOX_CMD_NONE = 0, + CSPL_MBOX_CMD_PAUSE = 1, + CSPL_MBOX_CMD_RESUME = 2, + CSPL_MBOX_CMD_REINIT = 3, + CSPL_MBOX_CMD_STOP_PRE_REINIT = 4, + CSPL_MBOX_CMD_UNKNOWN_CMD = -1, + CSPL_MBOX_CMD_INVALID_SEQUENCE = -2, +}; + +#endif /*__CS35L41_H__*/ diff --git a/techpack/audio/asoc/codecs/cs35l41/cs35l41.txt b/techpack/audio/asoc/codecs/cs35l41/cs35l41.txt new file mode 100644 index 000000000000..9ce49ac9ac68 --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/cs35l41.txt @@ -0,0 +1,184 @@ +CS35L41 Speaker Amplifier + +Required properties: + + - compatible : "cirrus,cs35l41" + "cirrus,cs35l40" + + - reg : the SPI chip select line for the device + + - VA-supply, VP-supply : power supplies for the device, + as covered in + Documentation/devicetree/bindings/regulator/regulator.txt. + +Optional properties: + - cirrus,sclk-force-output : Audio serial port SCLK force + output control. Forces the SCLK to continue to drive even + if no ASP_TXn channels are enabled. + + - cirrus,lrclk-force-output : Audio serial port LRCLK force + output control. Forces the LRCLK to continue to drive even + if no ASP_TXn channels are enabled. + + - cirrus,right-channel-amp : Boolean to determine which channel + the amplifier is to receive the audio data on. If present the + amplifier receives data on the right channel of I2S data. + If not present the amplifier receives data on the left + channel of I2S data + + - cirrus,boost-ctl-millivolt : Boost Voltage Value. Configures the + boost converter's output voltage in mV. The range is from 2550 mV to + 11000 mV with increments of 50 mV. + (Default) VP + + Boost hardware configuration: + + These three properties should be used together to specify the external + component configuration of the part. See section 4.3.6 of the datasheet + for details regarding how these values are used to configure the + digital boost converter's control loop. + + - cirrus,boost-peak-milliamp : Boost-converter peak current limit in mA. + Configures the peak current by monitoring the current through the boost FET. + Range starts at 1600 mA and goes to a maximum of 4500 mA with increments + of 50 mA. + (Default) 4.50 Amps + + - cirrus,boost-ind-nanohenry : Boost inductor value, expressed in nH. Valid + values include 1000, 1200, 1500 and 2200. + + - cirrus,boost-cap-microfarad : Total equivalent boost capacitance on the VBST + and VAMP pins, derated at 11 volts DC. The value must be rounded to the + nearest integer and expressed in uF. + + - cirrus,amp-gain-zc : Boolean to determine whether to use the amplifier + gain-change zero-crossing feature. If the feature is enabled, any + user-controlled amplifier gain change will occur on a zero-crossing point. + (Default) Disabled + + - cirrus,temp-warn-threshold : Amplifier overtemperature warning threshold. + Configures the threshold at which the overtemperature warning condition occurs. + When the threshold is met, the ovetemperature warning attenuation is applied + and the TEMP_WARN_EINT interrupt status bit is set. + If TEMP_WARN_MASK = 0, INTb is asserted. + + 0 = 105C + 1 = 115C + 2 = 125C (Default) + 3 = 135C + + - cirrus,noise-gate-enable : DSP Noise Gate feature. If present, noise + gate feature will be enabled. + + - cirrus,noise-gate-threshold : Threshold of audio signal input which the + noise gate considers the input audio to be at a low enough level to be + valid to enter a noise gating state of operation. + + 0 = -66 dBFS + 1 = -72 dBFS + 2 = -78 dBFS + 3 = -84 dBFS (default) + 4 = -90 dBFS + 5 = -96 dBFS + 6 = -102 dBFS + 7 = -108 dBFS + + - cirrus,noise-gate-delay : Time that the incoming audio signal must be + below the noise gate threshold prior to entering a noise gated state + + 0 = 5 ms + 1 = 10 ms + 2 = 25 ms + 3 = 50 ms (default) + 4 = 100 ms + 5 = 250 ms + 6 = 500 ms + 7 = 1 s + 8 = 5 s + 9 = 10 s + 10 = 20 s + 11 = 30 s + 12 = 40 s + 13 = 50 s + 14 = 60 s + 15 = 120 s + +Optional H/G Algorithm sub-node: + + The cs35l41 node can have a single "cirrus,classh-internal-algo" sub-node + that will disable automatic control of the internal H/G Algorithm. + + It is strongly recommended that the Datasheet be referenced when adjusting + or using these Class H Algorithm controls over the internal Algorithm. + Serious damage can occur to the Device and surrounding components. + + - cirrus,classh-internal-algo : Sub-node for the Internal Class H Algorithm + See Section 4.4 Internal Class H Algorithm in the Datasheet. + If not used, the device manages the ClassH Algorithm internally. + +Optional properties for the "cirrus,classh-internal-algo" Sub-node + + Section 7.9 Boost Control + - cirrus,classh-bst-overide : Boolean + - cirrus,classh-bst-max-limit + + Section 7.17 Class H, Weak-FET Control + - cirrus,classh-headroom + - cirrus,classh-release-rate + - cirrus,classh-mem-depth + - cirrus,classh-wk-fet-delay + - cirrus,classh-wk-fet-thld + + +Optional GPIO1 sub-node: + +The cs35l41 node can have an single "cirrus,gpio-config1" sub-node for +configuring the GPIO1 pin. + +- cirrus,gpio-polarity-invert : Boolean which specifies whether the GPIO1 +level is inverted. If this property is not present the level is not inverted. + +- cirrus,gpio-output-enable : Boolean which specifies whether the GPIO1 pin +is configured as an output. If this property is not present the +pin will be configured as an input. + +- cirrus,gpio-src-select : Configures the function of the GPIO1 pin. +Note that the options are different from the GPIO2 pin. + +0 = High Impedance (Default) +1 = GPIO +2 = Sync +3 = MCLK input + + +Optional GPIO2 sub-node: + +The cs35l41 node can have an single "cirrus,gpio-config2" sub-node for +configuring the GPIO1 pin. + +- cirrus,gpio-polarity-invert : Boolean which specifies whether the GPIO2 +level is inverted. If this property is not present the level is not inverted. + +- cirrus,gpio-output-enable : Boolean which specifies whether the GPIO2 pin +is configured as an output. If this property is not present the +pin will be configured as an input. + +- cirrus,gpio-src-select : Configures the function of the GPIO2 pin. +Note that the options are different from the GPIO1 pin. + +0 = High Impedance (Default) +1 = GPIO +2 = Open Drain INTB +3 = MCLK input +4 = Push-pull INTB (active low) +5 = Push-pull INT (active high) + + +Example: + +cs35l41: cs35l41@2 { + compatible = "cirrus,cs35l41"; + reg = <2>; + VA-supply = <&dummy_vreg>; + VP-supply = <&dummy_vreg>; +}; diff --git a/techpack/audio/asoc/codecs/cs35l41/wm_adsp.c b/techpack/audio/asoc/codecs/cs35l41/wm_adsp.c new file mode 100644 index 000000000000..2e028ac6ef36 --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/wm_adsp.c @@ -0,0 +1,5113 @@ +/* + * wm_adsp.c -- Wolfson ADSP support + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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. + */ +#define DEBUG +//#define WM_ADSP_DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "wm_adsp.h" + +#define adsp_crit(_dsp, fmt, ...) \ + dev_crit(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_err(_dsp, fmt, ...) \ + dev_err(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_warn(_dsp, fmt, ...) \ + dev_warn(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_info(_dsp, fmt, ...) \ + dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) +#define adsp_dbg(_dsp, fmt, ...) \ + dev_info(_dsp->dev, "DSP%d: " fmt, _dsp->num, ##__VA_ARGS__) + +#define MAXBULK 4 /* Max byte I2C bulk limit */ + +#define ADSP1_CONTROL_1 0x00 +#define ADSP1_CONTROL_2 0x02 +#define ADSP1_CONTROL_3 0x03 +#define ADSP1_CONTROL_4 0x04 +#define ADSP1_CONTROL_5 0x06 +#define ADSP1_CONTROL_6 0x07 +#define ADSP1_CONTROL_7 0x08 +#define ADSP1_CONTROL_8 0x09 +#define ADSP1_CONTROL_9 0x0A +#define ADSP1_CONTROL_10 0x0B +#define ADSP1_CONTROL_11 0x0C +#define ADSP1_CONTROL_12 0x0D +#define ADSP1_CONTROL_13 0x0F +#define ADSP1_CONTROL_14 0x10 +#define ADSP1_CONTROL_15 0x11 +#define ADSP1_CONTROL_16 0x12 +#define ADSP1_CONTROL_17 0x13 +#define ADSP1_CONTROL_18 0x14 +#define ADSP1_CONTROL_19 0x16 +#define ADSP1_CONTROL_20 0x17 +#define ADSP1_CONTROL_21 0x18 +#define ADSP1_CONTROL_22 0x1A +#define ADSP1_CONTROL_23 0x1B +#define ADSP1_CONTROL_24 0x1C +#define ADSP1_CONTROL_25 0x1E +#define ADSP1_CONTROL_26 0x20 +#define ADSP1_CONTROL_27 0x21 +#define ADSP1_CONTROL_28 0x22 +#define ADSP1_CONTROL_29 0x23 +#define ADSP1_CONTROL_30 0x24 +#define ADSP1_CONTROL_31 0x26 + +/* + * ADSP1 Control 19 + */ +#define ADSP1_WDMA_BUFFER_LENGTH_MASK 0x00FF /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define ADSP1_WDMA_BUFFER_LENGTH_SHIFT 0 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ +#define ADSP1_WDMA_BUFFER_LENGTH_WIDTH 8 /* DSP1_WDMA_BUFFER_LENGTH - [7:0] */ + + +/* + * ADSP1 Control 30 + */ +#define ADSP1_DBG_CLK_ENA 0x0008 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_MASK 0x0008 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_SHIFT 3 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_DBG_CLK_ENA_WIDTH 1 /* DSP1_DBG_CLK_ENA */ +#define ADSP1_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ +#define ADSP1_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ +#define ADSP1_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ +#define ADSP1_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ +#define ADSP1_START 0x0001 /* DSP1_START */ +#define ADSP1_START_MASK 0x0001 /* DSP1_START */ +#define ADSP1_START_SHIFT 0 /* DSP1_START */ +#define ADSP1_START_WIDTH 1 /* DSP1_START */ + +/* + * ADSP1 Control 31 + */ +#define ADSP1_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ +#define ADSP1_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ +#define ADSP1_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ + +#define ADSP2_CONTROL 0x0 +#define ADSP2_CLOCKING 0x1 +#define ADSP2V2_CLOCKING 0x2 +#define ADSP2_STATUS1 0x4 +#define ADSP2_WDMA_CONFIG_1 0x30 +#define ADSP2_WDMA_CONFIG_2 0x31 +#define ADSP2V2_WDMA_CONFIG_2 0x32 +#define ADSP2_RDMA_CONFIG_1 0x34 + +#define ADSP2_SCRATCH0 0x40 +#define ADSP2_SCRATCH1 0x41 +#define ADSP2_SCRATCH2 0x42 +#define ADSP2_SCRATCH3 0x43 + +#define ADSP2V2_SCRATCH0_1 0x40 +#define ADSP2V2_SCRATCH2_3 0x42 + +/* + * ADSP2 Control + */ + +#define ADSP2_MEM_ENA 0x0010 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_MASK 0x0010 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_SHIFT 4 /* DSP1_MEM_ENA */ +#define ADSP2_MEM_ENA_WIDTH 1 /* DSP1_MEM_ENA */ +#define ADSP2_SYS_ENA 0x0004 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_MASK 0x0004 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_SHIFT 2 /* DSP1_SYS_ENA */ +#define ADSP2_SYS_ENA_WIDTH 1 /* DSP1_SYS_ENA */ +#define ADSP2_CORE_ENA 0x0002 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_MASK 0x0002 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_SHIFT 1 /* DSP1_CORE_ENA */ +#define ADSP2_CORE_ENA_WIDTH 1 /* DSP1_CORE_ENA */ +#define ADSP2_START 0x0001 /* DSP1_START */ +#define ADSP2_START_MASK 0x0001 /* DSP1_START */ +#define ADSP2_START_SHIFT 0 /* DSP1_START */ +#define ADSP2_START_WIDTH 1 /* DSP1_START */ + +/* + * ADSP2 clocking + */ +#define ADSP2_CLK_SEL_MASK 0x0007 /* CLK_SEL_ENA */ +#define ADSP2_CLK_SEL_SHIFT 0 /* CLK_SEL_ENA */ +#define ADSP2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ + +/* + * ADSP2V2 clocking + */ +#define ADSP2V2_CLK_SEL_MASK 0x70000 /* CLK_SEL_ENA */ +#define ADSP2V2_CLK_SEL_SHIFT 16 /* CLK_SEL_ENA */ +#define ADSP2V2_CLK_SEL_WIDTH 3 /* CLK_SEL_ENA */ + +#define ADSP2V2_RATE_MASK 0x7800 /* DSP_RATE */ +#define ADSP2V2_RATE_SHIFT 11 /* DSP_RATE */ +#define ADSP2V2_RATE_WIDTH 4 /* DSP_RATE */ + +/* + * ADSP2 Status 1 + */ +#define ADSP2_RAM_RDY 0x0001 +#define ADSP2_RAM_RDY_MASK 0x0001 +#define ADSP2_RAM_RDY_SHIFT 0 +#define ADSP2_RAM_RDY_WIDTH 1 + +/* + * ADSP2 Lock support + */ +#define ADSP2_LOCK_CODE_0 0x5555 +#define ADSP2_LOCK_CODE_1 0xAAAA + +#define ADSP2_WATCHDOG 0x0A +#define ADSP2_BUS_ERR_ADDR 0x52 +#define ADSP2_REGION_LOCK_STATUS 0x64 +#define ADSP2_LOCK_REGION_1_LOCK_REGION_0 0x66 +#define ADSP2_LOCK_REGION_3_LOCK_REGION_2 0x68 +#define ADSP2_LOCK_REGION_5_LOCK_REGION_4 0x6A +#define ADSP2_LOCK_REGION_7_LOCK_REGION_6 0x6C +#define ADSP2_LOCK_REGION_9_LOCK_REGION_8 0x6E +#define ADSP2_LOCK_REGION_CTRL 0x7A +#define ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR 0x7C + +#define ADSP2_REGION_LOCK_ERR_MASK 0x8000 +#define ADSP2_SLAVE_ERR_MASK 0x4000 +#define ADSP2_WDT_TIMEOUT_STS_MASK 0x2000 +#define ADSP2_CTRL_ERR_PAUSE_ENA 0x0002 +#define ADSP2_CTRL_ERR_EINT 0x0001 + +#define ADSP2_BUS_ERR_ADDR_MASK 0x00FFFFFF +#define ADSP2_XMEM_ERR_ADDR_MASK 0x0000FFFF +#define ADSP2_PMEM_ERR_ADDR_MASK 0x7FFF0000 +#define ADSP2_PMEM_ERR_ADDR_SHIFT 16 +#define ADSP2_WDT_ENA_MASK 0xFFFFFFFD + +#define ADSP2_LOCK_REGION_SHIFT 16 + +#define ADSP_MAX_STD_CTRL_SIZE 512 + +#define WM_ADSP_ACKED_CTL_TIMEOUT_MS 100 +#define WM_ADSP_ACKED_CTL_N_QUICKPOLLS 10 +#define WM_ADSP_ACKED_CTL_MIN_VALUE 0 +#define WM_ADSP_ACKED_CTL_MAX_VALUE 0xFFFFFF + +/* + * Event control messages + */ +#define WM_ADSP_FW_EVENT_SHUTDOWN 0x000001 + +/* + * HALO system info + */ +#define HALO_SYS_INFO_XM_SRAM_SIZE 0x00010 +#define HALO_SYS_INFO_YM_SRAM_SIZE 0x00018 +#define HALO_SYS_INFO_XM_BANK_SIZE 0x00038 +#define HALO_SYS_INFO_YM_BANK_SIZE 0x0003c +#define HALO_AHBM_WINDOW_DEBUG_0 0x02040 +#define HALO_AHBM_WINDOW_DEBUG_1 0x02044 + +/* + * HALO core + */ +#define HALO_SAMPLE_RATE_RX1 0x00080 +#define HALO_SAMPLE_RATE_TX1 0x00280 +#define HALO_SCRATCH1 0x005c0 +#define HALO_CCM_CORE_CONTROL 0x41000 + +/* + * HALO Lock support + */ +#define HALO_MPU_UNLOCK_CODE_0 0x5555 +#define HALO_MPU_UNLOCK_CODE_1 0xaaaa + +/* + * HALO MPU banks + */ +#define HALO_MPU_XMEM_ACCESS_0 0x43000 +#define HALO_MPU_YMEM_ACCESS_0 0x43004 +#define HALO_MPU_WINDOW_ACCESS_0 0x43008 +#define HALO_MPU_XREG_ACCESS_0 0x4300C +#define HALO_MPU_YREG_ACCESS_0 0x43014 +#define HALO_MPU_XMEM_ACCESS_1 0x43018 +#define HALO_MPU_YMEM_ACCESS_1 0x4301C +#define HALO_MPU_WINDOW_ACCESS_1 0x43020 +#define HALO_MPU_XREG_ACCESS_1 0x43024 +#define HALO_MPU_YREG_ACCESS_1 0x4302C +#define HALO_MPU_XMEM_ACCESS_2 0x43030 +#define HALO_MPU_YMEM_ACCESS_2 0x43034 +#define HALO_MPU_WINDOW_ACCESS_2 0x43038 +#define HALO_MPU_XREG_ACCESS_2 0x4303C +#define HALO_MPU_YREG_ACCESS_2 0x43044 +#define HALO_MPU_XMEM_ACCESS_3 0x43048 +#define HALO_MPU_YMEM_ACCESS_3 0x4304C +#define HALO_MPU_WINDOW_ACCESS_3 0x43050 +#define HALO_MPU_XREG_ACCESS_3 0x43054 +#define HALO_MPU_YREG_ACCESS_3 0x4305C +#define HALO_MPU_XM_VIO_ADDR 0x43100 +#define HALO_MPU_XM_VIO_STATUS 0x43104 +#define HALO_MPU_YM_VIO_ADDR 0x43108 +#define HALO_MPU_YM_VIO_STATUS 0x4310C +#define HALO_MPU_PM_VIO_ADDR 0x43110 +#define HALO_MPU_PM_VIO_STATUS 0x43114 +#define HALO_MPU_LOCK_CONFIG 0x43140 + +/* + * HALO stream arb + */ +#define HALO_STREAM_ARB_MSTR0_CONFIG_0 0x45000 +#define HALO_STREAM_ARB_MSTR0_CONFIG_1 0x45004 +#define HALO_STREAM_ARB_MSTR0_CONFIG_2 0x45008 +#define HALO_STREAM_ARB_MSTR1_CONFIG_0 0x45010 +#define HALO_STREAM_ARB_MSTR1_CONFIG_1 0x45014 +#define HALO_STREAM_ARB_MSTR1_CONFIG_2 0x45018 +#define HALO_STREAM_ARB_MSTR2_CONFIG_0 0x45020 +#define HALO_STREAM_ARB_MSTR2_CONFIG_1 0x45024 +#define HALO_STREAM_ARB_MSTR2_CONFIG_2 0x45028 +#define HALO_STREAM_ARB_MSTR3_CONFIG_0 0x45030 +#define HALO_STREAM_ARB_MSTR3_CONFIG_1 0x45034 +#define HALO_STREAM_ARB_MSTR3_CONFIG_2 0x45038 +#define HALO_STREAM_ARB_MSTR4_CONFIG_0 0x45040 +#define HALO_STREAM_ARB_MSTR4_CONFIG_1 0x45044 +#define HALO_STREAM_ARB_MSTR4_CONFIG_2 0x45048 +#define HALO_STREAM_ARB_MSTR5_CONFIG_0 0x45050 +#define HALO_STREAM_ARB_MSTR5_CONFIG_1 0x45054 +#define HALO_STREAM_ARB_MSTR5_CONFIG_2 0x45058 + +#define HALO_STREAM_ARB_TX1_CONFIG_0 0x45200 +#define HALO_STREAM_ARB_TX1_CONFIG_1 0x45204 +#define HALO_STREAM_ARB_TX2_CONFIG_0 0x45208 +#define HALO_STREAM_ARB_TX2_CONFIG_1 0x4520C +#define HALO_STREAM_ARB_TX3_CONFIG_0 0x45210 +#define HALO_STREAM_ARB_TX3_CONFIG_1 0x45214 +#define HALO_STREAM_ARB_TX4_CONFIG_0 0x45218 +#define HALO_STREAM_ARB_TX4_CONFIG_1 0x4521C +#define HALO_STREAM_ARB_TX5_CONFIG_0 0x45220 +#define HALO_STREAM_ARB_TX5_CONFIG_1 0x45224 +#define HALO_STREAM_ARB_TX6_CONFIG_0 0x45228 +#define HALO_STREAM_ARB_TX6_CONFIG_1 0x4522C +#define HALO_STREAM_ARB_TX7_CONFIG_0 0x45230 +#define HALO_STREAM_ARB_TX7_CONFIG_1 0x45234 +#define HALO_STREAM_ARB_TX8_CONFIG_0 0x45238 +#define HALO_STREAM_ARB_TX8_CONFIG_1 0x4523C +#define HALO_STREAM_ARB_RX1_CONFIG_0 0x45400 +#define HALO_STREAM_ARB_RX1_CONFIG_1 0x45404 +#define HALO_STREAM_ARB_RX2_CONFIG_0 0x45408 +#define HALO_STREAM_ARB_RX2_CONFIG_1 0x4540C +#define HALO_STREAM_ARB_RX3_CONFIG_0 0x45410 +#define HALO_STREAM_ARB_RX3_CONFIG_1 0x45414 +#define HALO_STREAM_ARB_RX4_CONFIG_0 0x45418 +#define HALO_STREAM_ARB_RX4_CONFIG_1 0x4541C +#define HALO_STREAM_ARB_RX5_CONFIG_0 0x45420 +#define HALO_STREAM_ARB_RX5_CONFIG_1 0x45424 +#define HALO_STREAM_ARB_RX6_CONFIG_0 0x45428 +#define HALO_STREAM_ARB_RX6_CONFIG_1 0x4542C +#define HALO_STREAM_ARB_RX7_CONFIG_0 0x45430 +#define HALO_STREAM_ARB_RX7_CONFIG_1 0x45434 +#define HALO_STREAM_ARB_RX8_CONFIG_0 0x45438 +#define HALO_STREAM_ARB_RX8_CONFIG_1 0x4543C + +#define HALO_STREAM_ARB_IRQ0_CONFIG_0 0x45600 +#define HALO_STREAM_ARB_IRQ0_CONFIG_1 0x45604 +#define HALO_STREAM_ARB_IRQ0_CONFIG_2 0x45608 +#define HALO_STREAM_ARB_IRQ1_CONFIG_0 0x45610 +#define HALO_STREAM_ARB_IRQ1_CONFIG_1 0x45614 +#define HALO_STREAM_ARB_IRQ1_CONFIG_2 0x45618 +#define HALO_STREAM_ARB_IRQ2_CONFIG_0 0x45620 +#define HALO_STREAM_ARB_IRQ2_CONFIG_1 0x45624 +#define HALO_STREAM_ARB_IRQ2_CONFIG_2 0x45628 +#define HALO_STREAM_ARB_IRQ3_CONFIG_0 0x45630 +#define HALO_STREAM_ARB_IRQ3_CONFIG_1 0x45634 +#define HALO_STREAM_ARB_IRQ3_CONFIG_2 0x45638 +#define HALO_STREAM_ARB_IRQ4_CONFIG_0 0x45640 +#define HALO_STREAM_ARB_IRQ4_CONFIG_1 0x45644 +#define HALO_STREAM_ARB_IRQ4_CONFIG_2 0x45648 +#define HALO_STREAM_ARB_IRQ5_CONFIG_0 0x45650 +#define HALO_STREAM_ARB_IRQ5_CONFIG_1 0x45654 +#define HALO_STREAM_ARB_IRQ5_CONFIG_2 0x45658 +#define HALO_STREAM_ARB_IRQ6_CONFIG_0 0x45660 +#define HALO_STREAM_ARB_IRQ6_CONFIG_1 0x45664 +#define HALO_STREAM_ARB_IRQ6_CONFIG_2 0x45668 +#define HALO_STREAM_ARB_IRQ7_CONFIG_0 0x45670 +#define HALO_STREAM_ARB_IRQ7_CONFIG_1 0x45674 +#define HALO_STREAM_ARB_IRQ7_CONFIG_2 0x45678 + +#define HALO_INTP_CTL_NMI_CONTROL 0x46008 + +/* + * HALO_AHBM_WINDOW_DEBUG_1 + */ +#define HALO_AHBM_CORE_ERR_ADDR_MASK 0x0fffff00 +#define HALO_AHBM_CORE_ERR_ADDR_SHIFT 8 +#define HALO_AHBM_ADDR_ERR_MASK 0x00000080 +#define HALO_AHBM_LOCKED_ERR_MASK 0x00000040 +#define HALO_AHBM_SIZE_ERR_MASK 0x00000020 +#define HALO_AHBM_MODE_ERR_MASK 0x00000010 +#define HALO_AHBM_AHB_ERR_MASK 0x00000001 + +/* + * HALO_SAMPLE_RATE_[RX|TX]n + */ +#define HALO_DSP_RATE_SHIFT 0 +#define HALO_DSP_RATE_MASK 0x1f + +/* + * HALO_CCM_CORE_CONTROL + */ +#define HALO_CORE_EN 0x00000001 +#define HALO_CORE_EN_MASK 0x00000001 +#define HALO_CORE_EN_SHIFT 0 +#define HALO_CORE_EN_WIDTH 1 +#define HALO_CORE_RESET 0x00000200 + +/* + * HALO_MPU_?M_VIO_STATUS + */ +#define HALO_MPU_VIO_STS_MASK 0x007e0000 +#define HALO_MPU_VIO_STS_SHIFT 17 +#define HALO_MPU_VIO_ERR_MASK 0x00010000 +#define HALO_MPU_VIO_ERR_SHIFT 16 +#define HALO_MPU_VIO_ERR_WR_MASK 0x00008000 +#define HALO_MPU_VIO_ERR_WR_SHIFT 15 +#define HALO_MPU_VIO_ERR_SRC_MASK 0x00007fff +#define HALO_MPU_VIO_ERR_SRC_SHIFT 0 + +#define HALO_MPU_VIO_SRAM 0x01 +#define HALO_MPU_VIO_REG 0x02 +#define HALO_MPU_VIO_AHB 0x04 +#define HALO_MPU_VIO_EREG 0x08 +#define HALO_MPU_VIO_EXTERNAL_MEM 0x10 +#define HALO_MPU_VIO_NON_EXIST 0x20 + +/* + * HALO_STREAM_ARB_MSTRn_CONFIG_0 + */ +#define HALO_STREAM_ARB_MSTR_EN_MASK 0x1 + +/* + * HALO_STREAM_ARB_[TX|RX]n_CONFIG_0 + * HALO_STREAM_ARB_IRQn_CONFIG_0 + */ +#define HALO_STREAM_ARB_MSTR_SEL_DEFAULT 0xfc + +static const unsigned int halo_mpu_access[18] = { + HALO_MPU_WINDOW_ACCESS_0, + HALO_MPU_XREG_ACCESS_0, + HALO_MPU_YREG_ACCESS_0, + HALO_MPU_XMEM_ACCESS_1, + HALO_MPU_YMEM_ACCESS_1, + HALO_MPU_WINDOW_ACCESS_1, + HALO_MPU_XREG_ACCESS_1, + HALO_MPU_YREG_ACCESS_1, + HALO_MPU_XMEM_ACCESS_2, + HALO_MPU_YMEM_ACCESS_2, + HALO_MPU_WINDOW_ACCESS_2, + HALO_MPU_XREG_ACCESS_2, + HALO_MPU_YREG_ACCESS_2, + HALO_MPU_XMEM_ACCESS_3, + HALO_MPU_YMEM_ACCESS_3, + HALO_MPU_WINDOW_ACCESS_3, + HALO_MPU_XREG_ACCESS_3, + HALO_MPU_YREG_ACCESS_3, +}; + +struct wm_adsp_buf { + struct list_head list; + void *buf; +}; + +static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len, + struct list_head *list) +{ + struct wm_adsp_buf *buf = kzalloc(sizeof(*buf), GFP_KERNEL); + + if (buf == NULL) + return NULL; + + buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA); + if (!buf->buf) { + kfree(buf); + return NULL; + } + memcpy(buf->buf, src, len); + + if (list) + list_add_tail(&buf->list, list); + + return buf; +} + +static void wm_adsp_buf_free(struct list_head *list) +{ + while (!list_empty(list)) { + struct wm_adsp_buf *buf = list_first_entry(list, + struct wm_adsp_buf, + list); + list_del(&buf->list); + kfree(buf->buf); + kfree(buf); + } +} + +#define WM_ADSP_FW_MBC_VSS 0 +#define WM_ADSP_FW_HIFI 1 +#define WM_ADSP_FW_TX 2 +#define WM_ADSP_FW_TX_SPK 3 +#define WM_ADSP_FW_RX 4 +#define WM_ADSP_FW_RX_ANC 5 +#define WM_ADSP_FW_CTRL 6 +#define WM_ADSP_FW_ASR 7 +#define WM_ADSP_FW_TRACE 8 +#define WM_ADSP_FW_SPK_PROT 9 +#define WM_ADSP_FW_DIAG 10 +#define WM_ADSP_FW_CALIB 11 + +#define WM_ADSP_NUM_FW 12 + +#define AMBIENT_DEFAULT 30 +#define CAL_R_DEFAULT 8392 +#define CAL_STATUS_DEFAULT 1 + +static const char *wm_adsp_fw_text[WM_ADSP_NUM_FW] = { + [WM_ADSP_FW_MBC_VSS] = "MBC/VSS", + [WM_ADSP_FW_HIFI] = "MasterHiFi", + [WM_ADSP_FW_TX] = "Tx", + [WM_ADSP_FW_TX_SPK] = "Tx Speaker", + [WM_ADSP_FW_RX] = "Rx", + [WM_ADSP_FW_RX_ANC] = "Rx ANC", + [WM_ADSP_FW_CTRL] = "Voice Ctrl", + [WM_ADSP_FW_ASR] = "ASR Assist", + [WM_ADSP_FW_TRACE] = "Dbg Trace", + [WM_ADSP_FW_SPK_PROT] = "Protection", + [WM_ADSP_FW_DIAG] = "Diag", + [WM_ADSP_FW_CALIB] = "Diag Z", +}; + +struct wm_adsp_system_config_xm_hdr { + __be32 sys_enable; + __be32 fw_id; + __be32 fw_rev; + __be32 boot_status; + __be32 watchdog; + __be32 dma_buffer_size; + __be32 rdma[6]; + __be32 wdma[8]; + __be32 build_job_name[3]; + __be32 build_job_number; +}; + +struct wm_adsp_alg_xm_struct { + __be32 magic; + __be32 smoothing; + __be32 threshold; + __be32 host_buf_ptr; + __be32 start_seq; + __be32 high_water_mark; + __be32 low_water_mark; + __be64 smoothed_power; +}; + +struct wm_adsp_buffer { + __be32 X_buf_base; /* XM base addr of first X area */ + __be32 X_buf_size; /* Size of 1st X area in words */ + __be32 X_buf_base2; /* XM base addr of 2nd X area */ + __be32 X_buf_brk; /* Total X size in words */ + __be32 Y_buf_base; /* YM base addr of Y area */ + __be32 wrap; /* Total size X and Y in words */ + __be32 high_water_mark; /* Point at which IRQ is asserted */ + __be32 irq_count; /* bits 1-31 count IRQ assertions */ + __be32 irq_ack; /* acked IRQ count, bit 0 enables IRQ */ + __be32 next_write_index; /* word index of next write */ + __be32 next_read_index; /* word index of next read */ + __be32 error; /* error if any */ + __be32 oldest_block_index; /* word index of oldest surviving */ + __be32 requested_rewind; /* how many blocks rewind was done */ + __be32 reserved_space; /* internal */ + __be32 min_free; /* min free space since stream start */ + __be32 blocks_written[2]; /* total blocks written (64 bit) */ + __be32 words_written[2]; /* total words written (64 bit) */ +}; + +struct wm_adsp_compr; + +struct wm_adsp_compr_buf { + struct wm_adsp *dsp; + struct wm_adsp_compr *compr; + + struct wm_adsp_buffer_region *regions; + u32 host_buf_ptr; + + u32 error; + u32 irq_count; + int read_index; + int avail; +}; + +struct wm_adsp_compr { + struct wm_adsp *dsp; + struct wm_adsp_compr_buf *buf; + + struct snd_compr_stream *stream; + struct snd_compressed_buffer size; + + u32 *raw_buf; + unsigned int copied_total; + + unsigned int sample_rate; +}; + +#define WM_ADSP_DATA_WORD_SIZE 3 + +#define WM_ADSP_MIN_FRAGMENTS 1 +#define WM_ADSP_MAX_FRAGMENTS 256 +#define WM_ADSP_MIN_FRAGMENT_SIZE (64 * WM_ADSP_DATA_WORD_SIZE) +#define WM_ADSP_MAX_FRAGMENT_SIZE (4096 * WM_ADSP_DATA_WORD_SIZE) + +#define WM_ADSP_ALG_XM_STRUCT_MAGIC 0x49aec7 + +#define HOST_BUFFER_FIELD(field) \ + (offsetof(struct wm_adsp_buffer, field) / sizeof(__be32)) + +#define ALG_XM_FIELD(field) \ + (offsetof(struct wm_adsp_alg_xm_struct, field) / sizeof(__be32)) + +static int wm_adsp_buffer_init(struct wm_adsp *dsp); +static int wm_adsp_buffer_free(struct wm_adsp *dsp); + +struct wm_adsp_buffer_region { + unsigned int offset; + unsigned int cumulative_size; + unsigned int mem_type; + unsigned int base_addr; +}; + +struct wm_adsp_buffer_region_def { + unsigned int mem_type; + unsigned int base_offset; + unsigned int size_offset; +}; + +static const struct wm_adsp_buffer_region_def default_regions[] = { + { + .mem_type = WMFW_ADSP2_XM, + .base_offset = HOST_BUFFER_FIELD(X_buf_base), + .size_offset = HOST_BUFFER_FIELD(X_buf_size), + }, + { + .mem_type = WMFW_ADSP2_XM, + .base_offset = HOST_BUFFER_FIELD(X_buf_base2), + .size_offset = HOST_BUFFER_FIELD(X_buf_brk), + }, + { + .mem_type = WMFW_ADSP2_YM, + .base_offset = HOST_BUFFER_FIELD(Y_buf_base), + .size_offset = HOST_BUFFER_FIELD(wrap), + }, +}; + +struct wm_adsp_fw_caps { + u32 id; + struct snd_codec_desc desc; + int num_regions; + const struct wm_adsp_buffer_region_def *region_defs; +}; + +static const struct wm_adsp_fw_caps ctrl_caps[] = { + { + .id = SND_AUDIOCODEC_BESPOKE, + .desc = { + .max_ch = 1, + .sample_rates = { 16000 }, + .num_sample_rates = 1, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .num_regions = ARRAY_SIZE(default_regions), + .region_defs = default_regions, + }, +}; + +static const struct wm_adsp_fw_caps trace_caps[] = { + { + .id = SND_AUDIOCODEC_BESPOKE, + .desc = { + .max_ch = 8, + .sample_rates = { + 4000, 8000, 11025, 12000, 16000, 22050, + 24000, 32000, 44100, 48000, 64000, 88200, + 96000, 176400, 192000 + }, + .num_sample_rates = 15, + .formats = SNDRV_PCM_FMTBIT_S16_LE, + }, + .num_regions = ARRAY_SIZE(default_regions), + .region_defs = default_regions, + }, +}; + +static const struct { + const char *file; + int compr_direction; + int num_caps; + const struct wm_adsp_fw_caps *caps; + bool voice_trigger; +} wm_adsp_fw[WM_ADSP_NUM_FW] = { + [WM_ADSP_FW_MBC_VSS] = { .file = "mbc-vss" }, + [WM_ADSP_FW_HIFI] = { .file = "hifi" }, + [WM_ADSP_FW_TX] = { .file = "tx" }, + [WM_ADSP_FW_TX_SPK] = { .file = "tx-spk" }, + [WM_ADSP_FW_RX] = { .file = "rx" }, + [WM_ADSP_FW_RX_ANC] = { .file = "rx-anc" }, + [WM_ADSP_FW_CTRL] = { + .file = "ctrl", + .compr_direction = SND_COMPRESS_CAPTURE, + .num_caps = ARRAY_SIZE(ctrl_caps), + .caps = ctrl_caps, + .voice_trigger = true, + }, + [WM_ADSP_FW_ASR] = { .file = "asr" }, + [WM_ADSP_FW_TRACE] = { + .file = "trace", + .compr_direction = SND_COMPRESS_CAPTURE, + .num_caps = ARRAY_SIZE(trace_caps), + .caps = trace_caps, + }, + [WM_ADSP_FW_SPK_PROT] = { .file = "spk-prot" }, + [WM_ADSP_FW_DIAG] = { .file = "diag" }, + [WM_ADSP_FW_CALIB] = { .file = "diag-z" }, +}; + +struct wm_coeff_ctl_ops { + int (*xget)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + int (*xput)(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +}; + +struct wm_coeff_ctl { + const char *name; + const char *fw_name; + struct wm_adsp_alg_region alg_region; + struct wm_coeff_ctl_ops ops; + struct wm_adsp *dsp; + unsigned int enabled:1; + struct list_head list; + void *cache; + unsigned int offset; + size_t len; + unsigned int set:1; + struct soc_bytes_ext bytes_ext; + unsigned int flags; + unsigned int type; +}; + +static const char *wm_adsp_mem_region_name(unsigned int type) +{ + switch (type) { + case WMFW_ADSP1_PM: + return "PM"; + case WMFW_HALO_PM_PACKED: + return "PM_PACKED"; + case WMFW_ADSP1_DM: + return "DM"; + case WMFW_ADSP2_XM: + return "XM"; + case WMFW_HALO_XM_PACKED: + return "XM_PACKED"; + case WMFW_ADSP2_YM: + return "YM"; + case WMFW_HALO_YM_PACKED: + return "YM_PACKED"; + case WMFW_ADSP1_ZM: + return "ZM"; + default: + return NULL; + } +} +static int wm_halo_apply_calibration(struct snd_soc_dapm_widget *w); +static int wm_adsp_k_ctl_put(struct wm_adsp *dsp, const char *name, int value); +static int wm_adsp_k_ctl_get(struct wm_adsp *dsp, const char *name); + +#ifdef CONFIG_DEBUG_FS +static void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, const char *s) +{ + char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); + + kfree(dsp->wmfw_file_name); + dsp->wmfw_file_name = tmp; +} + +static void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, const char *s) +{ + char *tmp = kasprintf(GFP_KERNEL, "%s\n", s); + + kfree(dsp->bin_file_name); + dsp->bin_file_name = tmp; +} + +static void wm_adsp_debugfs_clear(struct wm_adsp *dsp) +{ + kfree(dsp->wmfw_file_name); + kfree(dsp->bin_file_name); + dsp->wmfw_file_name = NULL; + dsp->bin_file_name = NULL; +} + +static ssize_t wm_adsp_debugfs_wmfw_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wm_adsp *dsp = file->private_data; + ssize_t ret; + + mutex_lock(&dsp->pwr_lock); + + if (!dsp->wmfw_file_name || !dsp->booted) + ret = 0; + else + ret = simple_read_from_buffer(user_buf, count, ppos, + dsp->wmfw_file_name, + strlen(dsp->wmfw_file_name)); + + mutex_unlock(&dsp->pwr_lock); + return ret; +} + +static ssize_t wm_adsp_debugfs_bin_read(struct file *file, + char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct wm_adsp *dsp = file->private_data; + ssize_t ret; + + mutex_lock(&dsp->pwr_lock); + + if (!dsp->bin_file_name || !dsp->booted) + ret = 0; + else + ret = simple_read_from_buffer(user_buf, count, ppos, + dsp->bin_file_name, + strlen(dsp->bin_file_name)); + + mutex_unlock(&dsp->pwr_lock); + return ret; +} + +static const struct { + const char *name; + const struct file_operations fops; +} wm_adsp_debugfs_fops[] = { + { + .name = "wmfw_file_name", + .fops = { + .open = simple_open, + .read = wm_adsp_debugfs_wmfw_read, + }, + }, + { + .name = "bin_file_name", + .fops = { + .open = simple_open, + .read = wm_adsp_debugfs_bin_read, + }, + }, +}; + +static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, + struct snd_soc_codec *codec) +{ + struct dentry *root = NULL; + char *root_name; + int i; + + if (!codec->component.debugfs_root) { + adsp_err(dsp, "No codec debugfs root\n"); + goto err; + } + + root_name = kmalloc(PAGE_SIZE, GFP_KERNEL); + if (!root_name) + goto err; + + snprintf(root_name, PAGE_SIZE, "dsp%d", dsp->num); + root = debugfs_create_dir(root_name, codec->component.debugfs_root); + kfree(root_name); + + if (!root) + goto err; + + if (!debugfs_create_bool("booted", S_IRUGO, root, &dsp->booted)) + goto err; + + if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running)) + goto err; + + if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id)) + goto err; + + if (!debugfs_create_x32("fw_version", S_IRUGO, root, + &dsp->fw_id_version)) + goto err; + + for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) { + if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name, + S_IRUGO, root, dsp, + &wm_adsp_debugfs_fops[i].fops)) + goto err; + } + + dsp->debugfs_root = root; + return; + +err: + debugfs_remove_recursive(root); + adsp_err(dsp, "Failed to create debugfs\n"); +} + +static void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) +{ + wm_adsp_debugfs_clear(dsp); + debugfs_remove_recursive(dsp->debugfs_root); +} +#else +static inline void wm_adsp2_init_debugfs(struct wm_adsp *dsp, + struct snd_soc_codec *codec) +{ +} + +static inline void wm_adsp2_cleanup_debugfs(struct wm_adsp *dsp) +{ +} + +static inline void wm_adsp_debugfs_save_wmfwname(struct wm_adsp *dsp, + const char *s) +{ +} + +static inline void wm_adsp_debugfs_save_binname(struct wm_adsp *dsp, + const char *s) +{ +} + +static inline void wm_adsp_debugfs_clear(struct wm_adsp *dsp) +{ +} +#endif + +static int wm_adsp_fw_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = dsp[e->shift_l].fw; + + return 0; +} + +static int wm_adsp_fw_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + int ret = 0; + + if (ucontrol->value.enumerated.item[0] == dsp[e->shift_l].fw) + return 0; + + if (ucontrol->value.enumerated.item[0] >= WM_ADSP_NUM_FW) + return -EINVAL; + + mutex_lock(&dsp[e->shift_l].pwr_lock); + + if (dsp[e->shift_l].booted || dsp[e->shift_l].compr) + ret = -EBUSY; + else + dsp[e->shift_l].fw = ucontrol->value.enumerated.item[0]; + + mutex_unlock(&dsp[e->shift_l].pwr_lock); + + return ret; +} + +static int wm_adsp_cal_z_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = dsp->cal_z; + + return 0; +} + +static int wm_adsp_cal_z_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + dsp->cal_z = ucontrol->value.enumerated.item[0]; + dsp->cal_chksum = dsp->cal_z + CAL_STATUS_DEFAULT; + + dev_info(codec->dev, "cal_z = %d\n", dsp->cal_z); + + return 0; +} + +static int wm_adsp_ambient_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = dsp->ambient; + + return 0; +} + +static int wm_adsp_ambient_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + dsp->ambient = ucontrol->value.enumerated.item[0]; + + dev_info(codec->dev, "ambient = %d\n", dsp->ambient); + + return 0; +} + +static int wm_adsp_cal_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = dsp->cal_status; + + return 0; +} + +static int wm_adsp_cal_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + dsp->cal_status = ucontrol->value.enumerated.item[0]; + + dev_info(codec->dev, "cal_status = %d\n", dsp->cal_status); + + return 0; +} + +static int wm_adsp_cal_chksum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = dsp->cal_chksum; + + return 0; +} + +static int wm_adsp_cal_chksum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + dsp->cal_chksum = ucontrol->value.enumerated.item[0]; + + dev_info(codec->dev, "cal_chksum = %d\n", dsp->cal_chksum); + + return 0; +} + +static int wm_adsp_block_bypass_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = dsp->block_bypass; + + return 0; +} + +static int wm_adsp_block_bypass_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + dsp->block_bypass = ucontrol->value.enumerated.item[0]; + + switch(dsp->block_bypass) { + case 0: + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_IN_ENH", 0x00000000); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_EQ", 0x00000000); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_ACTI", 0x00000000); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_MBL", 0x00000000); + break; + case 1: + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_IN_ENH", 0x00400001); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_EQ", 0x00400001); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_ACTI", 0x00400001); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_MBL", 0x00400001); + break; + default: + break; + } + + dev_info(codec->dev, "block_bypass = %d\n", dsp->block_bypass); + + return 0; +} + +static int wm_adsp_block_bypass_in_enh_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.enumerated.item[0] = dsp->block_bypass_in_enh; + + return 0; +} + +static int wm_adsp_block_bypass_in_enh_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + dsp->block_bypass_in_enh = ucontrol->value.enumerated.item[0]; + + switch(dsp->block_bypass_in_enh) { + case 0: + dev_info(codec->dev, "block_bypass_in_enh = %d, put 0x00000000.\n", dsp->block_bypass_in_enh); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_IN_ENH", 0x00000000); + break; + case 1: + dev_info(codec->dev, "block_bypass_in_enh = %d, put 0x00400001.\n", dsp->block_bypass_in_enh); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd BYPASS_IN_ENH", 0x00400001); + break; + default: + break; + } + + dev_info(codec->dev, "block_bypass_in_enh = %d\n", dsp->block_bypass_in_enh); + + return 0; +} + +static const struct soc_enum wm_adsp_fw_enum[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 1, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 2, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 3, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 4, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 5, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), + SOC_ENUM_SINGLE(0, 6, ARRAY_SIZE(wm_adsp_fw_text), wm_adsp_fw_text), +}; +static const char *wm_adsp_block_bypass_text[2] = {"Off", "On"}; +static const struct soc_enum wm_adsp_block_bypass_enum[] = { + SOC_ENUM_SINGLE(0, 0, ARRAY_SIZE(wm_adsp_block_bypass_text), wm_adsp_block_bypass_text), +}; +const struct snd_kcontrol_new wm_adsp_fw_controls[] = { + SOC_ENUM_EXT("DSP1 Firmware", wm_adsp_fw_enum[0], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP2 Firmware", wm_adsp_fw_enum[1], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP3 Firmware", wm_adsp_fw_enum[2], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP4 Firmware", wm_adsp_fw_enum[3], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP5 Firmware", wm_adsp_fw_enum[4], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP6 Firmware", wm_adsp_fw_enum[5], + wm_adsp_fw_get, wm_adsp_fw_put), + SOC_ENUM_EXT("DSP7 Firmware", wm_adsp_fw_enum[6], + wm_adsp_fw_get, wm_adsp_fw_put), +}; + +const struct snd_kcontrol_new wm_adsp_cal_controls[] = { + /* In Halo DSP, values are 24-bit */ + SOC_SINGLE_EXT("DSP Set CAL_Z", SND_SOC_NOPM, 0, 0xFFFFFF, 0, + wm_adsp_cal_z_get, wm_adsp_cal_z_put), + SOC_SINGLE_EXT("DSP Set AMBIENT", SND_SOC_NOPM, 0, 0xFFFFFF, 0, + wm_adsp_ambient_get, wm_adsp_ambient_put), + SOC_SINGLE_EXT("DSP Set CAL_STATUS", SND_SOC_NOPM, 0, 0xFFFFFF, 0, + wm_adsp_cal_status_get, wm_adsp_cal_status_put), + SOC_SINGLE_EXT("DSP Set CAL_CHKSUM", SND_SOC_NOPM, 0, 0xFFFFFF, 0, + wm_adsp_cal_chksum_get, wm_adsp_cal_chksum_put), + SOC_ENUM_EXT("DSP Block Bypass", wm_adsp_block_bypass_enum[0], + wm_adsp_block_bypass_get, wm_adsp_block_bypass_put), + SOC_ENUM_EXT("DSP Block Bypass_IN_ENH", wm_adsp_block_bypass_enum[0], + wm_adsp_block_bypass_in_enh_get, wm_adsp_block_bypass_in_enh_put), +}; +EXPORT_SYMBOL_GPL(wm_adsp_cal_controls); + +static struct wm_adsp_region const *wm_adsp_find_region(struct wm_adsp *dsp, + int type) +{ + int i; + + for (i = 0; i < dsp->num_mems; i++) + if (dsp->mem[i].type == type) + return &dsp->mem[i]; + + return NULL; +} + +static unsigned int wm_adsp_region_to_reg(struct wm_adsp *dsp, + struct wm_adsp_region const *mem, + unsigned int offset) +{ + if (WARN_ON(!mem)) + return offset; + switch (dsp->type) { + case WMFW_ADSP1: + case WMFW_ADSP2: + switch (mem->type) { + case WMFW_ADSP1_PM: + return mem->base + (offset * 3); + case WMFW_ADSP1_DM: + return mem->base + (offset * 2); + case WMFW_ADSP2_XM: + return mem->base + (offset * 2); + case WMFW_ADSP2_YM: + return mem->base + (offset * 2); + case WMFW_ADSP1_ZM: + return mem->base + (offset * 2); + default: + WARN(1, "Unknown memory region type"); + return offset; + } + case WMFW_HALO: + switch (mem->type) { + case WMFW_ADSP2_XM: + return mem->base + (offset * 4); + case WMFW_ADSP2_YM: + return mem->base + (offset * 4); + case WMFW_HALO_XM_PACKED: + return (mem->base + (offset * 3)) & ~0x3; + case WMFW_HALO_YM_PACKED: + return (mem->base + (offset * 3)) & ~0x3; + case WMFW_HALO_PM_PACKED: + return mem->base + (offset * 5); + default: + WARN(1, "Unknown memory region type"); + return offset; + } + default: + WARN(1, "Unknown DSP type"); + return offset; + } +} +static int wm_adsp2_raw_read(size_t maxbulk, struct regmap *map, + unsigned int reg, void *val, size_t len) +{ + int ret; + size_t read_len = 0; + size_t toread_len; + + while ((len - read_len) > 0) { + toread_len = (len - read_len) > maxbulk ? + maxbulk : (len - read_len); + ret = regmap_raw_read(map, reg + read_len, + val + read_len, toread_len); + if (ret < 0) { + printk("%s failed, toread_len:%u reg base:%u reg:%u read_len:%u\n", + __func__, toread_len, reg, + reg + read_len, read_len); + return ret; + } + read_len += toread_len; + } + + return 0; +} + +static void wm_adsp2_show_fw_status(struct wm_adsp *dsp) +{ + u16 scratch[4]; + int ret; + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, dsp->base + ADSP2_SCRATCH0, + scratch, sizeof(scratch)); + if (ret) { + adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret); + return; + } + + adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", + be16_to_cpu(scratch[0]), + be16_to_cpu(scratch[1]), + be16_to_cpu(scratch[2]), + be16_to_cpu(scratch[3])); +} + +static void wm_adsp2v2_show_fw_status(struct wm_adsp *dsp) +{ + u32 scratch[2]; + int ret; + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, dsp->base + ADSP2V2_SCRATCH0_1, + scratch, sizeof(scratch)); + + if (ret) { + adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret); + return; + } + + scratch[0] = be32_to_cpu(scratch[0]); + scratch[1] = be32_to_cpu(scratch[1]); + + adsp_dbg(dsp, "FW SCRATCH 0:0x%x 1:0x%x 2:0x%x 3:0x%x\n", + scratch[0] & 0xFFFF, + scratch[0] >> 16, + scratch[1] & 0xFFFF, + scratch[1] >> 16); +} + +static void wm_halo_show_fw_status(struct wm_adsp *dsp) +{ + u32 scratch[4]; + int ret; + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, dsp->base + HALO_SCRATCH1, + scratch, sizeof(scratch)); + if (ret) { + adsp_err(dsp, "Failed to read SCRATCH regs: %d\n", ret); + return; + } + + adsp_dbg(dsp, "FW SCRATCH 1:0x%x 2:0x%x 3:0x%x 4:0x%x\n", + be32_to_cpu(scratch[0]), + be32_to_cpu(scratch[1]), + be32_to_cpu(scratch[2]), + be32_to_cpu(scratch[3])); +} + +static inline struct wm_coeff_ctl *bytes_ext_to_ctl(struct soc_bytes_ext *ext) +{ + return container_of(ext, struct wm_coeff_ctl, bytes_ext); +} + +static int wm_coeff_base_reg(struct wm_coeff_ctl *ctl, unsigned int *reg) +{ + const struct wm_adsp_alg_region *alg_region = &ctl->alg_region; + struct wm_adsp *dsp = ctl->dsp; + const struct wm_adsp_region *mem; + + mem = wm_adsp_find_region(dsp, alg_region->type); + if (!mem) { + adsp_err(dsp, "No base for region %x\n", + alg_region->type); + return -EINVAL; + } + + *reg = wm_adsp_region_to_reg(dsp, mem, + ctl->alg_region.base + ctl->offset); + + return 0; +} + +static int wm_coeff_info(struct snd_kcontrol *kctl, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + + switch (ctl->type) { + case WMFW_CTL_TYPE_ACKED: + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = WM_ADSP_ACKED_CTL_MIN_VALUE; + uinfo->value.integer.max = WM_ADSP_ACKED_CTL_MAX_VALUE; + uinfo->value.integer.step = 1; + uinfo->count = 1; + break; + default: + uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES; + uinfo->count = ctl->len; + break; + } + + return 0; +} + +static int wm_coeff_write_acked_control(struct wm_coeff_ctl *ctl, + unsigned int event_id) +{ + struct wm_adsp *dsp = ctl->dsp; + u32 val = cpu_to_be32(event_id); + unsigned int reg; + int i, ret; + + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; + + adsp_dbg(dsp, "Sending 0x%x to acked control alg 0x%x %s:0x%x\n", + event_id, ctl->alg_region.alg, + wm_adsp_mem_region_name(ctl->alg_region.type), ctl->offset); + + ret = regmap_raw_write(dsp->regmap, reg, &val, sizeof(val)); + if (ret) { + adsp_err(dsp, "Failed to write %x: %d\n", reg, ret); + return ret; + } + + /* + * Poll for ack, we initially poll at ~1ms intervals for firmwares + * that respond quickly, then go to ~10ms polls. A firmware is unlikely + * to ack instantly so we do the first 1ms delay before reading the + * control to avoid a pointless bus transaction + */ + for (i = 0; i < WM_ADSP_ACKED_CTL_TIMEOUT_MS;) { + switch (i) { + case 0 ... WM_ADSP_ACKED_CTL_N_QUICKPOLLS - 1: + usleep_range(1000, 2000); + i++; + break; + default: + usleep_range(10000, 20000); + i += 10; + break; + } + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, reg, &val, sizeof(val)); + if (ret) { + adsp_err(dsp, "Failed to read %x: %d\n", reg, ret); + return ret; + } + + if (val == 0) { + adsp_dbg(dsp, "Acked control ACKED at poll %u\n", i); + return 0; + } + } + + adsp_warn(dsp, "Acked control @0x%x alg:0x%x %s:0x%x timed out\n", + reg, ctl->alg_region.alg, + wm_adsp_mem_region_name(ctl->alg_region.type), + ctl->offset); + + return -ETIMEDOUT; +} + +static int wm_coeff_write_control(struct wm_coeff_ctl *ctl, + const void *buf, size_t len) +{ + struct wm_adsp *dsp = ctl->dsp; + void *scratch; + int ret; + unsigned int reg; + + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; + + scratch = kmemdup(buf, len, GFP_KERNEL | GFP_DMA); + if (!scratch) + return -ENOMEM; + + ret = regmap_raw_write(dsp->regmap, reg, scratch, + len); + if (ret) { + adsp_err(dsp, "Failed to write %zu bytes to %x: %d\n", + len, reg, ret); + kfree(scratch); + return ret; + } + adsp_dbg(dsp, "Wrote %zu bytes to %x\n", len, reg); + + kfree(scratch); + + return 0; +} + +static int wm_coeff_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + char *p = ucontrol->value.bytes.data; + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); + + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) + ret = -EPERM; + else + memcpy(ctl->cache, p, ctl->len); + + ctl->set = 1; + if (ctl->enabled && ctl->dsp->running) + ret = wm_coeff_write_control(ctl, p, ctl->len); + + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; +} + +static int wm_coeff_tlv_put(struct snd_kcontrol *kctl, + const unsigned int __user *bytes, unsigned int size) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); + + if (copy_from_user(ctl->cache, bytes, size)) { + ret = -EFAULT; + } else { + ctl->set = 1; + if (ctl->enabled && ctl->dsp->running) + ret = wm_coeff_write_control(ctl, ctl->cache, size); + else if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) + ret = -EPERM; + } + + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; +} + +static int wm_coeff_put_acked(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + unsigned int val = ucontrol->value.integer.value[0]; + int ret; + + if (val == 0) + return 0; /* 0 means no event */ + + mutex_lock(&ctl->dsp->pwr_lock); + + if (ctl->enabled && ctl->dsp->running) + ret = wm_coeff_write_acked_control(ctl, val); + else + ret = -EPERM; + + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; +} + +static int wm_coeff_read_control(struct wm_coeff_ctl *ctl, + void *buf, size_t len) +{ + struct wm_adsp *dsp = ctl->dsp; + void *scratch; + int ret; + unsigned int reg; + + ret = wm_coeff_base_reg(ctl, ®); + if (ret) + return ret; + + scratch = kmalloc(len, GFP_KERNEL | GFP_DMA); + if (!scratch) + return -ENOMEM; + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, reg, scratch, len); + if (ret) { + adsp_err(dsp, "Failed to read %zu bytes from %x: %d\n", + len, reg, ret); + kfree(scratch); + return ret; + } + adsp_dbg(dsp, "Read %zu bytes from %x\n", len, reg); + + memcpy(buf, scratch, len); + kfree(scratch); + + return 0; +} + +static int wm_coeff_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + char *p = ucontrol->value.bytes.data; + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); + + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { + if (ctl->enabled && ctl->dsp->running) + ret = wm_coeff_read_control(ctl, p, ctl->len); + else + ret = -EPERM; + } else { + if (!ctl->flags && ctl->enabled && ctl->dsp->running) + ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); + + memcpy(p, ctl->cache, ctl->len); + } + + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; +} + +static int wm_coeff_tlv_get(struct snd_kcontrol *kctl, + unsigned int __user *bytes, unsigned int size) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + int ret = 0; + + mutex_lock(&ctl->dsp->pwr_lock); + + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { + if (ctl->enabled && ctl->dsp->running) + ret = wm_coeff_read_control(ctl, ctl->cache, size); + else + ret = -EPERM; + } else { + if (!ctl->flags && ctl->enabled && ctl->dsp->running) + ret = wm_coeff_read_control(ctl, ctl->cache, size); + } + + if (!ret && copy_to_user(bytes, ctl->cache, size)) + ret = -EFAULT; + + mutex_unlock(&ctl->dsp->pwr_lock); + + return ret; +} + +static int wm_coeff_get_acked(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* + * Although it's not useful to read an acked control, we must satisfy + * user-side assumptions that all controls are readable and that a + * write of the same value should be filtered out (it's valid to send + * the same event number again to the firmware). We therefore return 0, + * meaning "no event" so valid event numbers will always be a change + */ + ucontrol->value.integer.value[0] = 0; + + return 0; +} + +struct wmfw_ctl_work { + struct wm_adsp *dsp; + struct wm_coeff_ctl *ctl; + struct work_struct work; +}; + +static unsigned int wmfw_convert_flags(unsigned int in, unsigned int len) +{ + unsigned int out, rd, wr, vol; + + if (len > ADSP_MAX_STD_CTRL_SIZE) { + rd = SNDRV_CTL_ELEM_ACCESS_TLV_READ; + wr = SNDRV_CTL_ELEM_ACCESS_TLV_WRITE; + vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE; + + out = SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK; + } else { + rd = SNDRV_CTL_ELEM_ACCESS_READ; + wr = SNDRV_CTL_ELEM_ACCESS_WRITE; + vol = SNDRV_CTL_ELEM_ACCESS_VOLATILE; + + out = 0; + } + + if (in) { + if (in & WMFW_CTL_FLAG_READABLE) + out |= rd; + if (in & WMFW_CTL_FLAG_WRITEABLE) + out |= wr; + if (in & WMFW_CTL_FLAG_VOLATILE) + out |= vol; + } else { + out |= rd | wr | vol; + } + + return out; +} + + +static int wmfw_add_ctl(struct wm_adsp *dsp, struct wm_coeff_ctl *ctl) +{ + struct snd_kcontrol_new *kcontrol; + int ret; + + if (!ctl || !ctl->name) + return -EINVAL; + + kcontrol = kzalloc(sizeof(*kcontrol), GFP_KERNEL); + if (!kcontrol) + return -ENOMEM; + + kcontrol->name = ctl->name; + kcontrol->info = wm_coeff_info; + kcontrol->iface = SNDRV_CTL_ELEM_IFACE_MIXER; + kcontrol->tlv.c = snd_soc_bytes_tlv_callback; + kcontrol->private_value = (unsigned long)&ctl->bytes_ext; + kcontrol->access = wmfw_convert_flags(ctl->flags, ctl->len); + + switch (ctl->type) { + case WMFW_CTL_TYPE_ACKED: + kcontrol->get = wm_coeff_get_acked; + kcontrol->put = wm_coeff_put_acked; + break; + default: + kcontrol->get = wm_coeff_get; + kcontrol->put = wm_coeff_put; + + ctl->bytes_ext.max = ctl->len; + ctl->bytes_ext.get = wm_coeff_tlv_get; + ctl->bytes_ext.put = wm_coeff_tlv_put; + break; + } + + ret = snd_soc_add_codec_controls(dsp->codec, kcontrol, 1); + if (ret < 0) + goto err_kcontrol; + + kfree(kcontrol); + + return 0; + +err_kcontrol: + kfree(kcontrol); + return ret; +} + +static int wm_coeff_init_control_caches(struct wm_adsp *dsp) +{ + struct wm_coeff_ctl *ctl; + int ret; + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (!ctl->enabled || ctl->set) + continue; + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) + continue; + + ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); + if (ret < 0) + return ret; + } + + return 0; +} + +static int wm_coeff_sync_controls(struct wm_adsp *dsp) +{ + struct wm_coeff_ctl *ctl; + int ret; + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (!ctl->enabled) + continue; + if (ctl->set && !(ctl->flags & WMFW_CTL_FLAG_VOLATILE)) { + ret = wm_coeff_write_control(ctl, ctl->cache, ctl->len); + if (ret < 0) + return ret; + } + } + + return 0; +} + +static void wm_adsp_signal_event_controls(struct wm_adsp *dsp, + unsigned int event) +{ + struct wm_coeff_ctl *ctl; + int ret; + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (ctl->type != WMFW_CTL_TYPE_HOSTEVENT) + continue; + + if (!ctl->enabled) + continue; + + ret = wm_coeff_write_acked_control(ctl, event); + if (ret) + adsp_warn(dsp, + "Failed to send 0x%x event to alg 0x%x (%d)\n", + event, ctl->alg_region.alg, ret); + } +} + +static void wm_adsp_ctl_work(struct work_struct *work) +{ + struct wmfw_ctl_work *ctl_work = container_of(work, + struct wmfw_ctl_work, + work); + + wmfw_add_ctl(ctl_work->dsp, ctl_work->ctl); + kfree(ctl_work); +} + +static void wm_adsp_free_ctl_blk(struct wm_coeff_ctl *ctl) +{ + kfree(ctl->cache); + kfree(ctl->name); + kfree(ctl); +} + +static int wm_adsp_create_control(struct wm_adsp *dsp, + const struct wm_adsp_alg_region *alg_region, + unsigned int offset, unsigned int len, + const char *subname, unsigned int subname_len, + unsigned int flags, unsigned int type) +{ + struct wm_coeff_ctl *ctl; + struct wmfw_ctl_work *ctl_work; + char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; + const char *region_name; + int ret; + + region_name = wm_adsp_mem_region_name(alg_region->type); + if (!region_name) { + adsp_err(dsp, "Unknown region type: %d\n", alg_region->type); + return -EINVAL; + } + + switch (dsp->fw_ver) { + case 0: + case 1: + snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, "DSP%d %s %x", + dsp->num, region_name, alg_region->alg); + break; + default: + ret = snprintf(name, SNDRV_CTL_ELEM_ID_NAME_MAXLEN, + "DSP%d%c %.12s %x", dsp->num, *region_name, + wm_adsp_fw_text[dsp->fw], alg_region->alg); + + /* Truncate the subname from the start if it is too long */ + if (subname) { + int avail = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret - 2; + int skip = 0; + + if (subname_len > avail) + skip = subname_len - avail; + + snprintf(name + ret, + SNDRV_CTL_ELEM_ID_NAME_MAXLEN - ret, " %.*s", + subname_len - skip, subname + skip); + } + break; + } + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (!strcmp(ctl->name, name)) { + if (!ctl->enabled) + ctl->enabled = 1; + return 0; + } + } + + ctl = kzalloc(sizeof(*ctl), GFP_KERNEL); + if (!ctl) + return -ENOMEM; + ctl->fw_name = wm_adsp_fw_text[dsp->fw]; + ctl->alg_region = *alg_region; + ctl->name = kmemdup(name, strlen(name) + 1, GFP_KERNEL); + if (!ctl->name) { + ret = -ENOMEM; + goto err_ctl; + } + ctl->enabled = 1; + ctl->set = 0; + ctl->ops.xget = wm_coeff_get; + ctl->ops.xput = wm_coeff_put; + ctl->dsp = dsp; + + ctl->flags = flags; + ctl->type = type; + ctl->offset = offset; + ctl->len = len; + ctl->cache = kzalloc(ctl->len, GFP_KERNEL); + if (!ctl->cache) { + ret = -ENOMEM; + goto err_ctl_name; + } + + list_add(&ctl->list, &dsp->ctl_list); + + if (flags & WMFW_CTL_FLAG_SYS) + return 0; + + ctl_work = kzalloc(sizeof(*ctl_work), GFP_KERNEL); + if (!ctl_work) { + ret = -ENOMEM; + goto err_ctl_cache; + } + + ctl_work->dsp = dsp; + ctl_work->ctl = ctl; + INIT_WORK(&ctl_work->work, wm_adsp_ctl_work); + schedule_work(&ctl_work->work); + + return 0; + +err_ctl_cache: + kfree(ctl->cache); +err_ctl_name: + kfree(ctl->name); +err_ctl: + kfree(ctl); + + return ret; +} + +struct wm_coeff_parsed_alg { + int id; + const u8 *name; + int name_len; + int ncoeff; +}; + +struct wm_coeff_parsed_coeff { + int offset; + int mem_type; + const u8 *name; + int name_len; + int ctl_type; + int flags; + int len; +}; + +static int wm_coeff_parse_string(int bytes, const u8 **pos, const u8 **str) +{ + int length; + + switch (bytes) { + case 1: + length = **pos; + break; + case 2: + length = le16_to_cpu(*((__le16 *)*pos)); + break; + default: + return 0; + } + + if (str) + *str = *pos + bytes; + + *pos += ((length + bytes) + 3) & ~0x03; + + return length; +} + +static int wm_coeff_parse_int(int bytes, const u8 **pos) +{ + int val = 0; + + switch (bytes) { + case 2: + val = le16_to_cpu(*((__le16 *)*pos)); + break; + case 4: + val = le32_to_cpu(*((__le32 *)*pos)); + break; + default: + break; + } + + *pos += bytes; + + return val; +} + +static inline void wm_coeff_parse_alg(struct wm_adsp *dsp, const u8 **data, + struct wm_coeff_parsed_alg *blk) +{ + const struct wmfw_adsp_alg_data *raw; + + switch (dsp->fw_ver) { + case 0: + case 1: + raw = (const struct wmfw_adsp_alg_data *)*data; + *data = raw->data; + + blk->id = le32_to_cpu(raw->id); + blk->name = raw->name; + blk->name_len = strlen(raw->name); + blk->ncoeff = le32_to_cpu(raw->ncoeff); + break; + default: + blk->id = wm_coeff_parse_int(sizeof(raw->id), data); + blk->name_len = wm_coeff_parse_string(sizeof(u8), data, + &blk->name); + wm_coeff_parse_string(sizeof(u16), data, NULL); + blk->ncoeff = wm_coeff_parse_int(sizeof(raw->ncoeff), data); + break; + } + + adsp_dbg(dsp, "Algorithm ID: %#x\n", blk->id); + adsp_dbg(dsp, "Algorithm name: %.*s\n", blk->name_len, blk->name); + adsp_dbg(dsp, "# of coefficient descriptors: %#x\n", blk->ncoeff); +} + +static inline void wm_coeff_parse_coeff(struct wm_adsp *dsp, const u8 **data, + struct wm_coeff_parsed_coeff *blk) +{ + const struct wmfw_adsp_coeff_data *raw; + const u8 *tmp; + int length; + + switch (dsp->fw_ver) { + case 0: + case 1: + raw = (const struct wmfw_adsp_coeff_data *)*data; + *data = *data + sizeof(raw->hdr) + le32_to_cpu(raw->hdr.size); + + blk->offset = le16_to_cpu(raw->hdr.offset); + blk->mem_type = le16_to_cpu(raw->hdr.type); + blk->name = raw->name; + blk->name_len = strlen(raw->name); + blk->ctl_type = le16_to_cpu(raw->ctl_type); + blk->flags = le16_to_cpu(raw->flags); + blk->len = le32_to_cpu(raw->len); + break; + default: + tmp = *data; + blk->offset = wm_coeff_parse_int(sizeof(raw->hdr.offset), &tmp); + blk->mem_type = wm_coeff_parse_int(sizeof(raw->hdr.type), &tmp); + length = wm_coeff_parse_int(sizeof(raw->hdr.size), &tmp); + blk->name_len = wm_coeff_parse_string(sizeof(u8), &tmp, + &blk->name); + wm_coeff_parse_string(sizeof(u8), &tmp, NULL); + wm_coeff_parse_string(sizeof(u16), &tmp, NULL); + blk->ctl_type = wm_coeff_parse_int(sizeof(raw->ctl_type), &tmp); + blk->flags = wm_coeff_parse_int(sizeof(raw->flags), &tmp); + blk->len = wm_coeff_parse_int(sizeof(raw->len), &tmp); + + *data = *data + sizeof(raw->hdr) + length; + break; + } + + adsp_dbg(dsp, "\tCoefficient type: %#x\n", blk->mem_type); + adsp_dbg(dsp, "\tCoefficient offset: %#x\n", blk->offset); + adsp_dbg(dsp, "\tCoefficient name: %.*s\n", blk->name_len, blk->name); + adsp_dbg(dsp, "\tCoefficient flags: %#x\n", blk->flags); + adsp_dbg(dsp, "\tALSA control type: %#x\n", blk->ctl_type); + adsp_dbg(dsp, "\tALSA control len: %#x\n", blk->len); +} + +static int wm_adsp_check_coeff_flags(struct wm_adsp *dsp, + const struct wm_coeff_parsed_coeff *coeff_blk, + unsigned int f_required, + unsigned int f_illegal) +{ + if ((coeff_blk->flags & f_illegal) || + ((coeff_blk->flags & f_required) != f_required)) { + adsp_err(dsp, "Illegal flags 0x%x for control type 0x%x\n", + coeff_blk->flags, coeff_blk->ctl_type); + return -EINVAL; + } + + return 0; +} + +static int wm_adsp_parse_coeff(struct wm_adsp *dsp, + const struct wmfw_region *region) +{ + struct wm_adsp_alg_region alg_region = {}; + struct wm_coeff_parsed_alg alg_blk; + struct wm_coeff_parsed_coeff coeff_blk; + const u8 *data = region->data; + int i, ret; + + wm_coeff_parse_alg(dsp, &data, &alg_blk); + for (i = 0; i < alg_blk.ncoeff; i++) { + wm_coeff_parse_coeff(dsp, &data, &coeff_blk); + + switch (coeff_blk.ctl_type) { + case SNDRV_CTL_ELEM_TYPE_BYTES: + break; + case WMFW_CTL_TYPE_ACKED: + if (coeff_blk.flags & WMFW_CTL_FLAG_SYS) + continue; /* ignore */ + + ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); + if (ret) + return -EINVAL; + break; + case WMFW_CTL_TYPE_HOSTEVENT: + ret = wm_adsp_check_coeff_flags(dsp, &coeff_blk, + WMFW_CTL_FLAG_SYS | + WMFW_CTL_FLAG_VOLATILE | + WMFW_CTL_FLAG_WRITEABLE | + WMFW_CTL_FLAG_READABLE, + 0); + if (ret) + return -EINVAL; + break; + default: + adsp_err(dsp, "Unknown control type: %d\n", + coeff_blk.ctl_type); + return -EINVAL; + } + + alg_region.type = coeff_blk.mem_type; + alg_region.alg = alg_blk.id; + + ret = wm_adsp_create_control(dsp, &alg_region, + coeff_blk.offset, + coeff_blk.len, + coeff_blk.name, + coeff_blk.name_len, + coeff_blk.flags, + coeff_blk.ctl_type); + if (ret < 0) + adsp_err(dsp, "Failed to create control: %.*s, %d\n", + coeff_blk.name_len, coeff_blk.name, ret); + } + + return 0; +} + +static int wm_adsp_load(struct wm_adsp *dsp) +{ + LIST_HEAD(buf_list); + const struct firmware *firmware; + struct regmap *regmap = dsp->regmap; + unsigned int pos = 0; + const struct wmfw_header *header; + const struct wmfw_adsp1_sizes *adsp1_sizes; + const struct wmfw_adsp2_sizes *adsp2_sizes; + const struct wmfw_footer *footer; + const struct wmfw_region *region; + const struct wm_adsp_region *mem; + const char *region_name; + char *file, *text = NULL; + struct wm_adsp_buf *buf; +#ifdef WM_ADSP_DEBUG + void *bufVerify; +#endif + unsigned int reg; + int regions = 0; + int ret, offset, type, sizes; +#ifdef WM_ADSP_DEBUG + size_t i; + bool verifyOk = true; + int tempA, tempB; + int* pTempA, *pTempB; + int max_failures = 666666; + int num_failures = 0; + int whileLoopCount = 0; +#endif + file = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (file == NULL) + return -ENOMEM; + + snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.wmfw", dsp->part, dsp->num, + wm_adsp_fw[dsp->fw].file); + file[PAGE_SIZE - 1] = '\0'; + + ret = request_firmware(&firmware, file, dsp->dev); + if (ret != 0) { + adsp_err(dsp, "Failed to request '%s'\n", file); + goto out; + } + ret = -EINVAL; + + pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); + if (pos >= firmware->size) { + adsp_err(dsp, "%s: file too short, %zu bytes\n", + file, firmware->size); + goto out_fw; + } + + header = (void *)&firmware->data[0]; + + if (memcmp(&header->magic[0], "WMFW", 4) != 0) { + adsp_err(dsp, "%s: invalid magic\n", file); + goto out_fw; + } + + switch (dsp->type) { + case WMFW_ADSP1: + case WMFW_ADSP2: + switch (header->ver) { + case 0: + adsp_warn(dsp, "%s: Deprecated file format %d\n", + file, header->ver); + break; + case 1: + case 2: + break; + default: + adsp_err(dsp, "%s: unknown file format %d\n", + file, header->ver); + goto out_fw; + } + break; + case WMFW_HALO: + switch (header->ver) { + case 1: + case 2: + /* + * we are required to load these for testing purposes + * but this format is not allowed for production fw + */ + adsp_warn(dsp, + "%s: Not a production firmware (deprecated file format %d)\n", + file, header->ver); + break; + case 3: + break; + default: + adsp_err(dsp, "%s: unknown file format %d\n", + file, header->ver); + goto out_fw; + } + } + + adsp_info(dsp, "Firmware version: %d\n", header->ver); + dsp->fw_ver = header->ver; + + if (header->core != dsp->type) { + adsp_err(dsp, "%s: invalid core %d != %d\n", + file, header->core, dsp->type); + goto out_fw; + } + + switch (dsp->type) { + case WMFW_ADSP1: + pos = sizeof(*header) + sizeof(*adsp1_sizes) + sizeof(*footer); + adsp1_sizes = (void *)&(header[1]); + footer = (void *)&(adsp1_sizes[1]); + sizes = sizeof(*adsp1_sizes); + + adsp_dbg(dsp, "%s: %d DM, %d PM, %d ZM\n", + file, le32_to_cpu(adsp1_sizes->dm), + le32_to_cpu(adsp1_sizes->pm), + le32_to_cpu(adsp1_sizes->zm)); + break; + + case WMFW_HALO: + case WMFW_ADSP2: + pos = sizeof(*header) + sizeof(*adsp2_sizes) + sizeof(*footer); + adsp2_sizes = (void *)&(header[1]); + footer = (void *)&(adsp2_sizes[1]); + sizes = sizeof(*adsp2_sizes); + + adsp_dbg(dsp, "%s: %d XM, %d YM %d PM, %d ZM\n", + file, le32_to_cpu(adsp2_sizes->xm), + le32_to_cpu(adsp2_sizes->ym), + le32_to_cpu(adsp2_sizes->pm), + le32_to_cpu(adsp2_sizes->zm)); + break; + + default: + WARN(1, "Unknown DSP type"); + goto out_fw; + } + + if (le32_to_cpu(header->len) != sizeof(*header) + + sizes + sizeof(*footer)) { + adsp_err(dsp, "%s: unexpected header length %d\n", + file, le32_to_cpu(header->len)); + goto out_fw; + } + + adsp_dbg(dsp, "%s: timestamp %llu\n", file, + le64_to_cpu(footer->timestamp)); + + while (pos < firmware->size && + pos - firmware->size > sizeof(*region)) { +#ifdef WM_ADSP_DEBUG + num_failures = 0; +#endif + region = (void *)&(firmware->data[pos]); + region_name = "Unknown"; + reg = 0; + text = NULL; + offset = le32_to_cpu(region->offset) & 0xffffff; + type = be32_to_cpu(region->type) & 0xff; + mem = wm_adsp_find_region(dsp, type); + + switch (type) { + case WMFW_NAME_TEXT: + region_name = "Firmware name"; + text = kzalloc(le32_to_cpu(region->len) + 1, + GFP_KERNEL); + break; + case WMFW_ALGORITHM_DATA: + region_name = "Algorithm"; + ret = wm_adsp_parse_coeff(dsp, region); + if (ret != 0) + goto out_fw; + break; + case WMFW_INFO_TEXT: + region_name = "Information"; + text = kzalloc(le32_to_cpu(region->len) + 1, + GFP_KERNEL); + break; + case WMFW_ABSOLUTE: + region_name = "Absolute"; + reg = offset; + break; + case WMFW_ADSP1_PM: + case WMFW_ADSP1_DM: + case WMFW_ADSP2_XM: + case WMFW_ADSP2_YM: + case WMFW_ADSP1_ZM: + case WMFW_HALO_PM_PACKED: + case WMFW_HALO_XM_PACKED: + case WMFW_HALO_YM_PACKED: + region_name = wm_adsp_mem_region_name(type); + reg = wm_adsp_region_to_reg(dsp, mem, offset); + break; + default: + adsp_warn(dsp, + "%s.%d: Unknown region type %x at %d(%x)\n", + file, regions, type, pos, pos); + break; + } + + adsp_dbg(dsp, "%s.%d: %d bytes at %d in %s\n", file, + regions, le32_to_cpu(region->len), offset, + region_name); + + if ((pos + le32_to_cpu(region->len) + sizeof(*region)) > + firmware->size) { + adsp_err(dsp, + "%s.%d: %s region len %d bytes exceeds file length %zu\n", + file, regions, region_name, + le32_to_cpu(region->len), firmware->size); + ret = -EINVAL; + goto out_fw; + } + + if (text) { + memcpy(text, region->data, le32_to_cpu(region->len)); + adsp_info(dsp, "%s: %s\n", file, text); + kfree(text); + text = NULL; + } + + if (reg) { + buf = wm_adsp_buf_alloc(region->data, + le32_to_cpu(region->len), + &buf_list); + if (!buf) { + adsp_err(dsp, "Out of memory\n"); + ret = -ENOMEM; + goto out_fw; + } +#ifdef WM_ADSP_DEBUG + bufVerify = vmalloc(le32_to_cpu(region->len)); + if (!bufVerify) { + adsp_err(dsp, "Could not allocate memory for verification buffer\n"); + ret = -ENOMEM; + goto out_fw; + } +#endif + + ret = regmap_raw_write_async(regmap, reg, buf->buf, + le32_to_cpu(region->len)); + + if (ret != 0) { + adsp_err(dsp, + "%s.%d: Failed to write %d bytes at %d in %s: %d\n", + file, regions, + le32_to_cpu(region->len), offset, + region_name, ret); + goto out_fw; + } +#ifdef WM_ADSP_DEBUG + /* abb. 3/5/18 - DEBUG. Wait for this write to complete + Then we will read back the registers and verify contents */ + adsp_info(dsp, "%s: Waiting to complete async write\n", __func__); + ret = regmap_async_complete(regmap); + if (ret != 0) { + adsp_err(dsp, "[1] Failed to complete async write: %d\n", ret); + goto out_fw; + } + adsp_err(dsp, "%s: Async write completed\n", __func__); + + ret = wm_adsp2_raw_read(MAXBULK, regmap, reg, bufVerify, le32_to_cpu(region->len)); + + adsp_err(dsp, "%s: Beginning Verification (loop %d)\n", __func__, whileLoopCount); + adsp_err(dsp, "%s: Total loop length: %d\n", __func__, le32_to_cpu(region->len) / 4); + pTempA = (int *)buf->buf; + pTempB = (int *)bufVerify; + for (i=0; i < le32_to_cpu(region->len) / 4; i++) { + tempA = pTempA[i]; + tempB = pTempB[i]; + + if (tempA != tempB) { + adsp_err(dsp, "** Verify failed on reg 0x%x at i=%zu (wrote 0x%x vs read 0x%x)\n", + reg, i, tempA, tempB); + verifyOk = false; + num_failures++; + } + + if (num_failures >= max_failures) { + adsp_err(dsp, "** Too many failed register verifies (hit max of %d). Exiting\n", + max_failures); + break; + } + } + + vfree(bufVerify); +#endif + } + + pos += le32_to_cpu(region->len) + sizeof(*region); + regions++; +#ifdef WM_ADSP_DEBUG + whileLoopCount++; +#endif + } + + ret = regmap_async_complete(regmap); + if (ret != 0) { + adsp_err(dsp, "Failed to complete async write: %d\n", ret); + goto out_fw; + } + + if (pos > firmware->size) + adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", + file, regions, pos - firmware->size); + + wm_adsp_debugfs_save_wmfwname(dsp, file); + +out_fw: + regmap_async_complete(regmap); + wm_adsp_buf_free(&buf_list); + release_firmware(firmware); + kfree(text); +out: + kfree(file); +#ifdef WM_ADSP_DEBUG + adsp_err(dsp, "wm_adsp_load- with verifyOk = %d and ret = %d", + verifyOk, ret); +#endif + return ret; +} + +static void wm_adsp_ctl_fixup_base(struct wm_adsp *dsp, + const struct wm_adsp_alg_region *alg_region) +{ + struct wm_coeff_ctl *ctl; + + list_for_each_entry(ctl, &dsp->ctl_list, list) { + if (ctl->fw_name == wm_adsp_fw_text[dsp->fw] && + alg_region->alg == ctl->alg_region.alg && + alg_region->type == ctl->alg_region.type) { + ctl->alg_region.base = alg_region->base; + } + } +} + +static void *wm_adsp_read_algs(struct wm_adsp *dsp, size_t n_algs, + unsigned int pos, unsigned int len) +{ + void *alg; + int ret; + __be32 val; + + if (n_algs == 0) { + adsp_err(dsp, "No algorithms\n"); + return ERR_PTR(-EINVAL); + } + + if (n_algs > 1024) { + adsp_err(dsp, "Algorithm count %zx excessive\n", n_algs); + return ERR_PTR(-EINVAL); + } + + /* Read the terminator first to validate the length */ + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, pos + len, &val, sizeof(val)); + if (ret != 0) { + adsp_err(dsp, "Failed to read algorithm list end: %d\n", + ret); + return ERR_PTR(ret); + } + + if (be32_to_cpu(val) != 0xbedead) + adsp_warn(dsp, "Algorithm list end %x 0x%x != 0xbedead\n", + pos + len, be32_to_cpu(val)); + + alg = kzalloc(len * 2, GFP_KERNEL | GFP_DMA); + if (!alg) + return ERR_PTR(-ENOMEM); + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, pos, alg, len * 2); + if (ret != 0) { + adsp_err(dsp, "Failed to read algorithm list: %d\n", ret); + kfree(alg); + return ERR_PTR(ret); + } + + return alg; +} + +static struct wm_adsp_alg_region * + wm_adsp_find_alg_region(struct wm_adsp *dsp, int type, unsigned int id) +{ + struct wm_adsp_alg_region *alg_region; + + list_for_each_entry(alg_region, &dsp->alg_regions, list) { + if (id == alg_region->alg && type == alg_region->type) + return alg_region; + } + + return NULL; +} + +static struct wm_adsp_alg_region *wm_adsp_create_region(struct wm_adsp *dsp, + int type, __be32 id, + __be32 base) +{ + struct wm_adsp_alg_region *alg_region; + + alg_region = kzalloc(sizeof(*alg_region), GFP_KERNEL); + if (!alg_region) + return ERR_PTR(-ENOMEM); + + alg_region->type = type; + alg_region->alg = be32_to_cpu(id); + alg_region->base = be32_to_cpu(base); + + list_add_tail(&alg_region->list, &dsp->alg_regions); + + if (dsp->fw_ver > 0) + wm_adsp_ctl_fixup_base(dsp, alg_region); + + return alg_region; +} + +static void wm_adsp_free_alg_regions(struct wm_adsp *dsp) +{ + struct wm_adsp_alg_region *alg_region; + + while (!list_empty(&dsp->alg_regions)) { + alg_region = list_first_entry(&dsp->alg_regions, + struct wm_adsp_alg_region, + list); + list_del(&alg_region->list); + kfree(alg_region); + } +} + +static int wm_adsp1_setup_algs(struct wm_adsp *dsp) +{ + struct wmfw_adsp1_id_hdr adsp1_id; + struct wmfw_adsp1_alg_hdr *adsp1_alg; + struct wm_adsp_alg_region *alg_region; + const struct wm_adsp_region *mem; + unsigned int pos, len; + size_t n_algs; + int i, ret; + + mem = wm_adsp_find_region(dsp, WMFW_ADSP1_DM); + if (WARN_ON(!mem)) + return -EINVAL; + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, mem->base, &adsp1_id, + sizeof(adsp1_id)); + if (ret != 0) { + adsp_err(dsp, "Failed to read algorithm info: %d\n", + ret); + return ret; + } + + n_algs = be32_to_cpu(adsp1_id.n_algs); + dsp->fw_id = be32_to_cpu(adsp1_id.fw.id); + adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", + dsp->fw_id, + (be32_to_cpu(adsp1_id.fw.ver) & 0xff0000) >> 16, + (be32_to_cpu(adsp1_id.fw.ver) & 0xff00) >> 8, + be32_to_cpu(adsp1_id.fw.ver) & 0xff, + n_algs); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, + adsp1_id.fw.id, adsp1_id.zm); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, + adsp1_id.fw.id, adsp1_id.dm); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + pos = sizeof(adsp1_id) / 2; + len = (sizeof(*adsp1_alg) * n_algs) / 2; + + adsp1_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len); + if (IS_ERR(adsp1_alg)) + return PTR_ERR(adsp1_alg); + + for (i = 0; i < n_algs; i++) { + adsp_info(dsp, "%d: ID %x v%d.%d.%d DM@%x ZM@%x\n", + i, be32_to_cpu(adsp1_alg[i].alg.id), + (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(adsp1_alg[i].alg.ver) & 0xff, + be32_to_cpu(adsp1_alg[i].dm), + be32_to_cpu(adsp1_alg[i].zm)); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_DM, + adsp1_alg[i].alg.id, + adsp1_alg[i].dm); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + if (dsp->fw_ver == 0) { + if (i + 1 < n_algs) { + len = be32_to_cpu(adsp1_alg[i + 1].dm); + len -= be32_to_cpu(adsp1_alg[i].dm); + len *= 4; + wm_adsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); + } else { + adsp_warn(dsp, "Missing length info for region DM with ID %x\n", + be32_to_cpu(adsp1_alg[i].alg.id)); + } + } + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP1_ZM, + adsp1_alg[i].alg.id, + adsp1_alg[i].zm); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + if (dsp->fw_ver == 0) { + if (i + 1 < n_algs) { + len = be32_to_cpu(adsp1_alg[i + 1].zm); + len -= be32_to_cpu(adsp1_alg[i].zm); + len *= 4; + wm_adsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); + } else { + adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", + be32_to_cpu(adsp1_alg[i].alg.id)); + } + } + } + +out: + kfree(adsp1_alg); + return ret; +} + +static int wm_adsp2_setup_algs(struct wm_adsp *dsp) +{ + struct wmfw_adsp2_id_hdr adsp2_id; + struct wmfw_adsp2_alg_hdr *adsp2_alg; + struct wm_adsp_alg_region *alg_region; + const struct wm_adsp_region *mem; + unsigned int pos, len; + size_t n_algs; + int i, ret; + + mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); + if (WARN_ON(!mem)) + return -EINVAL; + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, mem->base, &adsp2_id, + sizeof(adsp2_id)); + if (ret != 0) { + adsp_err(dsp, "Failed to read algorithm info: %d\n", + ret); + return ret; + } + + n_algs = be32_to_cpu(adsp2_id.n_algs); + dsp->fw_id = be32_to_cpu(adsp2_id.fw.id); + dsp->fw_id_version = be32_to_cpu(adsp2_id.fw.ver); + dsp->fw_vendor_id = 0; + adsp_info(dsp, "Firmware: %x v%d.%d.%d, %zu algorithms\n", + dsp->fw_id, + (dsp->fw_id_version & 0xff0000) >> 16, + (dsp->fw_id_version & 0xff00) >> 8, + dsp->fw_id_version & 0xff, + n_algs); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, + adsp2_id.fw.id, adsp2_id.xm); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, + adsp2_id.fw.id, adsp2_id.ym); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + switch (dsp->type) { + case WMFW_HALO: + pos = sizeof(adsp2_id); + len = sizeof(*adsp2_alg) * n_algs; + break; + default: + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, + adsp2_id.fw.id, adsp2_id.zm); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + pos = sizeof(adsp2_id) / 2; + len = (sizeof(*adsp2_alg) * n_algs) / 2; + break; + } + + adsp2_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len); + if (IS_ERR(adsp2_alg)) + return PTR_ERR(adsp2_alg); + + for (i = 0; i < n_algs; i++) { + adsp_info(dsp, + "%d: ID %x v%d.%d.%d XM@%x YM@%x ZM@%x\n", + i, be32_to_cpu(adsp2_alg[i].alg.id), + (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(adsp2_alg[i].alg.ver) & 0xff, + be32_to_cpu(adsp2_alg[i].xm), + be32_to_cpu(adsp2_alg[i].ym), + be32_to_cpu(adsp2_alg[i].zm)); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, + adsp2_alg[i].alg.id, + adsp2_alg[i].xm); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + if (dsp->fw_ver == 0) { + if (i + 1 < n_algs) { + len = be32_to_cpu(adsp2_alg[i + 1].xm); + len -= be32_to_cpu(adsp2_alg[i].xm); + len *= 4; + wm_adsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); + } else { + adsp_warn(dsp, "Missing length info for region XM with ID %x\n", + be32_to_cpu(adsp2_alg[i].alg.id)); + } + } + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, + adsp2_alg[i].alg.id, + adsp2_alg[i].ym); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + if (dsp->fw_ver == 0) { + if (i + 1 < n_algs) { + len = be32_to_cpu(adsp2_alg[i + 1].ym); + len -= be32_to_cpu(adsp2_alg[i].ym); + len *= 4; + wm_adsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); + } else { + adsp_warn(dsp, "Missing length info for region YM with ID %x\n", + be32_to_cpu(adsp2_alg[i].alg.id)); + } + } + + /* no ZM on HALO */ + if (dsp->type == WMFW_HALO) + continue; + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_ZM, + adsp2_alg[i].alg.id, + adsp2_alg[i].zm); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + if (dsp->fw_ver == 0) { + if (i + 1 < n_algs) { + len = be32_to_cpu(adsp2_alg[i + 1].zm); + len -= be32_to_cpu(adsp2_alg[i].zm); + len *= 4; + wm_adsp_create_control(dsp, alg_region, 0, + len, NULL, 0, 0, + SNDRV_CTL_ELEM_TYPE_BYTES); + } else { + adsp_warn(dsp, "Missing length info for region ZM with ID %x\n", + be32_to_cpu(adsp2_alg[i].alg.id)); + } + } + } + +out: + kfree(adsp2_alg); + return ret; +} + +static int wm_halo_setup_algs(struct wm_adsp *dsp) +{ + struct wmfw_halo_id_hdr halo_id; + struct wmfw_halo_alg_hdr *halo_alg; + struct wm_adsp_alg_region *alg_region; + const struct wm_adsp_region *mem; + unsigned int pos, len, block_rev; + size_t n_algs; + int i, ret; + + mem = wm_adsp_find_region(dsp, WMFW_ADSP2_XM); + if (WARN_ON(!mem)) + return -EINVAL; + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, mem->base, &halo_id, + sizeof(halo_id)); + if (ret != 0) { + adsp_err(dsp, "Failed to read algorithm info: %d\n", + ret); + return ret; + } + + block_rev = be32_to_cpu(halo_id.fw.block_rev) >> 16; + switch (block_rev) { + case 3: + break; + default: + adsp_err(dsp, "Unknown firmware ID block version 0x%x\n", + block_rev); + return -EINVAL; + } + + n_algs = be32_to_cpu(halo_id.n_algs); + dsp->fw_id = be32_to_cpu(halo_id.fw.id); + dsp->fw_id_version = be32_to_cpu(halo_id.fw.ver); + dsp->fw_vendor_id = be32_to_cpu(halo_id.fw.vendor_id); + adsp_info(dsp, "Firmware: %x vendor: 0x%x v%d.%d.%d, %zu algorithms\n", + dsp->fw_id, + dsp->fw_vendor_id, + (dsp->fw_id_version & 0xff0000) >> 16, + (dsp->fw_id_version & 0xff00) >> 8, + dsp->fw_id_version & 0xff, + n_algs); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, + halo_id.fw.id, halo_id.xm_base); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + alg_region = wm_adsp_create_region(dsp, WMFW_HALO_XM_PACKED, + halo_id.fw.id, halo_id.xm_base); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, + halo_id.fw.id, halo_id.ym_base); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + alg_region = wm_adsp_create_region(dsp, WMFW_HALO_YM_PACKED, + halo_id.fw.id, halo_id.ym_base); + if (IS_ERR(alg_region)) + return PTR_ERR(alg_region); + + pos = sizeof(halo_id); + len = (sizeof(*halo_alg) * n_algs); + + halo_alg = wm_adsp_read_algs(dsp, n_algs, mem->base + pos, len); + if (IS_ERR(halo_alg)) + return PTR_ERR(halo_alg); + + for (i = 0; i < n_algs; i++) { + adsp_info(dsp, + "%d: ID %x v%d.%d.%d XM@%x YM@%x\n", + i, be32_to_cpu(halo_alg[i].alg.id), + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff0000) >> 16, + (be32_to_cpu(halo_alg[i].alg.ver) & 0xff00) >> 8, + be32_to_cpu(halo_alg[i].alg.ver) & 0xff, + be32_to_cpu(halo_alg[i].xm_base), + be32_to_cpu(halo_alg[i].ym_base)); + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_XM, + halo_alg[i].alg.id, + halo_alg[i].xm_base); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + + alg_region = wm_adsp_create_region(dsp, WMFW_HALO_XM_PACKED, + halo_alg[i].alg.id, + halo_alg[i].xm_base); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + + alg_region = wm_adsp_create_region(dsp, WMFW_ADSP2_YM, + halo_alg[i].alg.id, + halo_alg[i].ym_base); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + + alg_region = wm_adsp_create_region(dsp, WMFW_HALO_YM_PACKED, + halo_alg[i].alg.id, + halo_alg[i].ym_base); + if (IS_ERR(alg_region)) { + ret = PTR_ERR(alg_region); + goto out; + } + } + +out: + kfree(halo_alg); + return ret; +} + +static int wm_adsp_load_coeff(struct wm_adsp *dsp) +{ + LIST_HEAD(buf_list); + struct regmap *regmap = dsp->regmap; + struct wmfw_coeff_hdr *hdr; + struct wmfw_coeff_item *blk; + const struct firmware *firmware; + const struct wm_adsp_region *mem; + struct wm_adsp_alg_region *alg_region; + const char *region_name; + int ret, pos, blocks, type, offset, reg; + char *file; + struct wm_adsp_buf *buf; + + file = kzalloc(PAGE_SIZE, GFP_KERNEL); + if (file == NULL) + return -ENOMEM; + + snprintf(file, PAGE_SIZE, "%s-dsp%d-%s.bin", dsp->part, dsp->num, + wm_adsp_fw[dsp->fw].file); + file[PAGE_SIZE - 1] = '\0'; + + ret = request_firmware(&firmware, file, dsp->dev); + if (ret != 0) { + adsp_warn(dsp, "Failed to request '%s'\n", file); + ret = 0; + goto out; + } + ret = -EINVAL; + + if (sizeof(*hdr) >= firmware->size) { + adsp_err(dsp, "%s: file too short, %zu bytes\n", + file, firmware->size); + goto out_fw; + } + + hdr = (void *)&firmware->data[0]; + if (memcmp(hdr->magic, "WMDR", 4) != 0) { + adsp_err(dsp, "%s: invalid magic\n", file); + goto out_fw; + } + + switch (be32_to_cpu(hdr->rev) & 0xff) { + case 1: + break; + default: + adsp_err(dsp, "%s: Unsupported coefficient file format %d\n", + file, be32_to_cpu(hdr->rev) & 0xff); + ret = -EINVAL; + goto out_fw; + } + + adsp_dbg(dsp, "%s: v%d.%d.%d\n", file, + (le32_to_cpu(hdr->ver) >> 16) & 0xff, + (le32_to_cpu(hdr->ver) >> 8) & 0xff, + le32_to_cpu(hdr->ver) & 0xff); + + pos = le32_to_cpu(hdr->len); + + blocks = 0; + while (pos < firmware->size && + pos - firmware->size > sizeof(*blk)) { + blk = (void *)(&firmware->data[pos]); + + type = le16_to_cpu(blk->type); + offset = le16_to_cpu(blk->offset); + + adsp_dbg(dsp, "%s.%d: %x v%d.%d.%d\n", + file, blocks, le32_to_cpu(blk->id), + (le32_to_cpu(blk->ver) >> 16) & 0xff, + (le32_to_cpu(blk->ver) >> 8) & 0xff, + le32_to_cpu(blk->ver) & 0xff); + adsp_dbg(dsp, "%s.%d: %d bytes at 0x%x in %x\n", + file, blocks, le32_to_cpu(blk->len), offset, type); + + reg = 0; + region_name = "Unknown"; + switch (type) { + case (WMFW_NAME_TEXT << 8): + case (WMFW_INFO_TEXT << 8): + break; + case (WMFW_ABSOLUTE << 8): + /* + * Old files may use this for global + * coefficients. + */ + if (le32_to_cpu(blk->id) == dsp->fw_id && + offset == 0) { + region_name = "global coefficients"; + mem = wm_adsp_find_region(dsp, type); + if (!mem) { + adsp_err(dsp, "No ZM\n"); + break; + } + reg = wm_adsp_region_to_reg(dsp, mem, 0); + + } else { + region_name = "register"; + reg = offset; + } + break; + + case WMFW_ADSP1_DM: + case WMFW_ADSP1_ZM: + case WMFW_ADSP2_XM: + case WMFW_ADSP2_YM: + case WMFW_HALO_XM_PACKED: + case WMFW_HALO_YM_PACKED: + case WMFW_HALO_PM_PACKED: + adsp_dbg(dsp, "%s.%d: %d bytes in %x for %x\n", + file, blocks, le32_to_cpu(blk->len), + type, le32_to_cpu(blk->id)); + + mem = wm_adsp_find_region(dsp, type); + if (!mem) { + adsp_err(dsp, "No base for region %x\n", type); + break; + } + + alg_region = wm_adsp_find_alg_region(dsp, type, + le32_to_cpu(blk->id)); + if (alg_region) { + reg = alg_region->base; + reg = wm_adsp_region_to_reg(dsp, mem, reg); + reg += offset; + } else { + adsp_err(dsp, "No %x for algorithm %x\n", + type, le32_to_cpu(blk->id)); + } + break; + + default: + adsp_err(dsp, "%s.%d: Unknown region type %x at %d\n", + file, blocks, type, pos); + break; + } + + if (reg) { + if ((pos + le32_to_cpu(blk->len) + sizeof(*blk)) > + firmware->size) { + adsp_err(dsp, + "%s.%d: %s region len %d bytes exceeds file length %zu\n", + file, blocks, region_name, + le32_to_cpu(blk->len), + firmware->size); + ret = -EINVAL; + goto out_fw; + } + + buf = wm_adsp_buf_alloc(blk->data, + le32_to_cpu(blk->len), + &buf_list); + if (!buf) { + adsp_err(dsp, "Out of memory\n"); + ret = -ENOMEM; + goto out_fw; + } + + adsp_dbg(dsp, "%s.%d: Writing %d bytes at %x\n", + file, blocks, le32_to_cpu(blk->len), + reg); + ret = regmap_raw_write_async(regmap, reg, buf->buf, + le32_to_cpu(blk->len)); + if (ret != 0) { + adsp_err(dsp, + "%s.%d: Failed to write to %x in %s: %d\n", + file, blocks, reg, region_name, ret); + } + } + + pos += (le32_to_cpu(blk->len) + sizeof(*blk) + 3) & ~0x03; + blocks++; + } + + ret = regmap_async_complete(regmap); + if (ret != 0) + adsp_err(dsp, "Failed to complete async write: %d\n", ret); + + if (pos > firmware->size) + adsp_warn(dsp, "%s.%d: %zu bytes at end of file\n", + file, blocks, pos - firmware->size); + + wm_adsp_debugfs_save_binname(dsp, file); + +out_fw: + regmap_async_complete(regmap); + release_firmware(firmware); + wm_adsp_buf_free(&buf_list); +out: + kfree(file); + return ret; +} + +int wm_adsp1_init(struct wm_adsp *dsp) +{ + INIT_LIST_HEAD(&dsp->alg_regions); + + mutex_init(&dsp->pwr_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp1_init); + +int wm_adsp1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + struct wm_coeff_ctl *ctl; + int ret; + unsigned int val; + + dsp->codec = codec; + + mutex_lock(&dsp->pwr_lock); + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, ADSP1_SYS_ENA); + + /* + * For simplicity set the DSP clock rate to be the + * SYSCLK rate rather than making it configurable. + */ + if (dsp->sysclk_reg) { + ret = regmap_read(dsp->regmap, dsp->sysclk_reg, &val); + if (ret != 0) { + adsp_err(dsp, "Failed to read SYSCLK state: %d\n", + ret); + goto err_mutex; + } + + val = (val & dsp->sysclk_mask) >> dsp->sysclk_shift; + + ret = regmap_update_bits(dsp->regmap, + dsp->base + ADSP1_CONTROL_31, + ADSP1_CLK_SEL_MASK, val); + if (ret != 0) { + adsp_err(dsp, "Failed to set clock rate: %d\n", + ret); + goto err_mutex; + } + } + + ret = wm_adsp_load(dsp); + if (ret != 0) + goto err_ena; + + ret = wm_adsp1_setup_algs(dsp); + if (ret != 0) + goto err_ena; + + ret = wm_adsp_load_coeff(dsp); + if (ret != 0) + goto err_ena; + + /* Initialize caches for enabled and unset controls */ + ret = wm_coeff_init_control_caches(dsp); + if (ret != 0) + goto err_ena; + + /* Sync set controls */ + ret = wm_coeff_sync_controls(dsp); + if (ret != 0) + goto err_ena; + + dsp->booted = true; + + /* Start the core running */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, + ADSP1_CORE_ENA | ADSP1_START); + + dsp->running = true; + break; + + case SND_SOC_DAPM_PRE_PMD: + dsp->running = false; + dsp->booted = false; + + /* Halt the core */ + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_CORE_ENA | ADSP1_START, 0); + + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_19, + ADSP1_WDMA_BUFFER_LENGTH_MASK, 0); + + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, 0); + + list_for_each_entry(ctl, &dsp->ctl_list, list) + ctl->enabled = 0; + + + wm_adsp_free_alg_regions(dsp); + break; + + default: + break; + } + + mutex_unlock(&dsp->pwr_lock); + + return 0; + +err_ena: + regmap_update_bits(dsp->regmap, dsp->base + ADSP1_CONTROL_30, + ADSP1_SYS_ENA, 0); +err_mutex: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp1_event); + +static int wm_adsp2_ena(struct wm_adsp *dsp) +{ + unsigned int val; + int ret, count; + + switch (dsp->rev) { + case 0: + ret = regmap_update_bits_async(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, ADSP2_SYS_ENA); + if (ret != 0) + return ret; + break; + default: + break; + } + + /* Wait for the RAM to start, should be near instantaneous */ + for (count = 0; count < 10; ++count) { + ret = regmap_read(dsp->regmap, dsp->base + ADSP2_STATUS1, &val); + if (ret != 0) + return ret; + + if (val & ADSP2_RAM_RDY) + break; + + usleep_range(250, 500); + } + + if (!(val & ADSP2_RAM_RDY)) { + adsp_err(dsp, "Failed to start DSP RAM\n"); + return -EBUSY; + } + + adsp_dbg(dsp, "RAM ready after %d polls\n", count); + + return 0; +} + +static void wm_adsp2_boot_work(struct work_struct *work) +{ + struct wm_adsp *dsp = container_of(work, + struct wm_adsp, + boot_work); + int ret; + + mutex_lock(&dsp->pwr_lock); + + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, ADSP2_MEM_ENA); + if (ret != 0) + goto err_mutex; + + ret = wm_adsp2_ena(dsp); + if (ret != 0) + goto err_mem; + + ret = wm_adsp_load(dsp); + if (ret != 0) + goto err_ena; + + ret = wm_adsp2_setup_algs(dsp); + if (ret != 0) + goto err_ena; + + ret = wm_adsp_load_coeff(dsp); + if (ret != 0) + goto err_ena; + + /* Initialize caches for enabled and unset controls */ + ret = wm_coeff_init_control_caches(dsp); + if (ret != 0) + goto err_ena; + + switch (dsp->rev) { + case 0: + /* Turn DSP back off until we are ready to run */ + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, 0); + if (ret != 0) + goto err_ena; + break; + default: + break; + } + + dsp->booted = true; + + mutex_unlock(&dsp->pwr_lock); + + return; + +err_ena: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); +err_mem: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); +err_mutex: + mutex_unlock(&dsp->pwr_lock); +} + +static int wm_halo_set_rate_block(struct wm_adsp *dsp, + unsigned int rate_base, + unsigned int n_rates, + const u8 *rate_cache) +{ + unsigned int addr = dsp->base + rate_base, val; + int ret, i; + + for (i = 0; i < n_rates; ++i) { + val = rate_cache[i] << HALO_DSP_RATE_SHIFT; + + ret = regmap_update_bits(dsp->regmap, + addr + (i * 8), + HALO_DSP_RATE_MASK, + val); + if (ret) { + adsp_err(dsp, "Failed to set rate: %d\n", ret); + return ret; + } + + adsp_dbg(dsp, "Set rate %d to 0x%x\n", i, val); + } + + return 0; +} + +static int wm_halo_clear_stream_arb(struct wm_adsp *dsp) +{ + struct regmap *regmap = dsp->regmap; + unsigned int dspbase = dsp->base, reg; + u32 values[3] = {0, 0, 0}; + int ret; + + /* disable stream arbiter masters */ + for (reg = dspbase + HALO_STREAM_ARB_MSTR0_CONFIG_0; + reg <= dspbase + HALO_STREAM_ARB_MSTR5_CONFIG_0; + reg += 0x10) { + ret = regmap_update_bits(regmap, reg, + HALO_STREAM_ARB_MSTR_EN_MASK, 0); + if (ret) + goto error; + } + + /* clear stream arbiter masters */ + for (reg = dspbase + HALO_STREAM_ARB_MSTR0_CONFIG_0; + reg <= dspbase + HALO_STREAM_ARB_MSTR5_CONFIG_0; + reg += 0x10) { + ret = regmap_bulk_write(regmap, reg, values, 3); + if (ret) + goto error; + } + + /* clear stream arbiter channel configs */ + for (reg = dspbase + HALO_STREAM_ARB_TX1_CONFIG_0; + reg <= dspbase + HALO_STREAM_ARB_RX8_CONFIG_0; + reg += 0x8) { + ret = regmap_write(regmap, reg, + HALO_STREAM_ARB_MSTR_SEL_DEFAULT); + if (ret) + goto error; + } + + /* clear stream arbiter interrupt registers */ + values[0] = HALO_STREAM_ARB_MSTR_SEL_DEFAULT; + for (reg = dspbase + HALO_STREAM_ARB_IRQ0_CONFIG_0; + reg <= dspbase + HALO_STREAM_ARB_IRQ7_CONFIG_1; + reg += 0x10) { + ret = regmap_bulk_write(regmap, reg, values, 2); + if (ret) + goto error; + } + return 0; + +error: + adsp_err(dsp, + "Error while clearing stream arbiter config (reg 0x%x): %d\n", + reg, ret); + return ret; +} + +static int wm_halo_configure_mpu(struct wm_adsp *dsp) +{ + struct regmap *regmap = dsp->regmap; + int i = 0, len = 0, ret; + unsigned int sysinfo_base = dsp->base_sysinfo, dsp_base = dsp->base; + unsigned int xm_sz, xm_bank_sz, ym_sz, ym_bank_sz; + unsigned int xm_acc_cfg, ym_acc_cfg; + unsigned int lock_cfg; + + ret = regmap_read(regmap, sysinfo_base + HALO_SYS_INFO_XM_BANK_SIZE, + &xm_bank_sz); + if (ret) { + adsp_err(dsp, "Failed to read XM bank size.\n"); + goto err; + } + + if (!xm_bank_sz) { + adsp_err(dsp, "Failed to configure MPU (XM_BANK_SIZE = 0)\n"); + goto err; + } + + ret = regmap_read(regmap, sysinfo_base + HALO_SYS_INFO_YM_BANK_SIZE, + &ym_bank_sz); + if (ret) { + adsp_err(dsp, "Failed to read YM bank size.\n"); + goto err; + } + + if (!ym_bank_sz) { + adsp_err(dsp, "Failed to configure MPU (YM_BANK_SIZE = 0)\n"); + goto err; + } + + ret = regmap_read(regmap, sysinfo_base + HALO_SYS_INFO_XM_SRAM_SIZE, + &xm_sz); + if (ret) { + adsp_err(dsp, "Failed to read XM size.\n"); + goto err; + } + + ret = regmap_read(regmap, sysinfo_base + HALO_SYS_INFO_YM_SRAM_SIZE, + &ym_sz); + if (ret) { + adsp_err(dsp, "Failed to read YM size.\n"); + goto err; + } + + adsp_dbg(dsp, + "XM size 0x%x XM bank size 0x%x YM size 0x%x YM bank size 0x%x\n", + xm_sz, xm_bank_sz, ym_sz, ym_bank_sz); + + /* calculate amount of banks to unlock */ + xm_acc_cfg = (1 << (xm_sz / xm_bank_sz)) - 1; + ym_acc_cfg = (1 << (ym_sz / ym_bank_sz)) - 1; + + /* unlock MPU */ + ret = regmap_write(regmap, dsp_base + HALO_MPU_LOCK_CONFIG, + HALO_MPU_UNLOCK_CODE_0); + if (ret) { + adsp_err(dsp, "Error while unlocking MPU: %d\n", ret); + goto err; + } + + ret = regmap_write(regmap, dsp_base + HALO_MPU_LOCK_CONFIG, + HALO_MPU_UNLOCK_CODE_1); + if (ret) { + adsp_err(dsp, "Error while unlocking MPU: %d\n", ret); + goto err; + } + + adsp_dbg(dsp, "Unlocking XM (cfg: %x) and YM (cfg: %x)", + xm_acc_cfg, ym_acc_cfg); + + /* unlock XMEM and YMEM */ + ret = regmap_write(regmap, dsp_base + HALO_MPU_XMEM_ACCESS_0, + xm_acc_cfg); + if (ret) + goto err; + + ret = regmap_write(regmap, dsp_base + HALO_MPU_YMEM_ACCESS_0, + ym_acc_cfg); + if (ret) + goto err; + + len = sizeof(halo_mpu_access) / sizeof(halo_mpu_access[0]); + lock_cfg = (dsp->unlock_all) ? 0xFFFFFFFF : 0; + /* configure all other banks */ + for (i = 0; i < len; i++) { /* TODO: think if can be done without LUT */ + ret = regmap_write(regmap, dsp_base + halo_mpu_access[i], + lock_cfg); + if (ret) + goto err; + } + + /* lock MPU */ + ret = regmap_write(regmap, dsp_base + HALO_MPU_LOCK_CONFIG, 0); + if (ret) + adsp_err(dsp, "Error while locking MPU: %d\n", ret); + +err: + return ret; +} + +static void wm_halo_boot_work(struct work_struct *work) +{ + struct wm_adsp *dsp = container_of(work, + struct wm_adsp, + boot_work); + int ret; + + mutex_lock(&dsp->pwr_lock); + + ret = wm_adsp_load(dsp); + if (ret != 0) + goto err; + + switch (dsp->fw_ver) { + case 1: + case 2: + ret = wm_adsp2_setup_algs(dsp); + if (ret != 0) + goto err; + break; + default: + ret = wm_halo_setup_algs(dsp); + if (ret != 0) + goto err; + break; + } + + ret = wm_adsp_load_coeff(dsp); + if (ret != 0) + goto err; + + /* Initialize caches for enabled and unset controls */ + ret = wm_coeff_init_control_caches(dsp); + if (ret != 0) + goto err; + + dsp->booted = true; + + mutex_unlock(&dsp->pwr_lock); + + return; + +err: + regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, + HALO_CORE_EN, 0); + mutex_unlock(&dsp->pwr_lock); +} + +static void wm_adsp2_set_dspclk(struct wm_adsp *dsp, unsigned int freq) +{ + int ret; + + switch (dsp->rev) { + case 0: + ret = regmap_update_bits_async(dsp->regmap, + dsp->base + ADSP2_CLOCKING, + ADSP2_CLK_SEL_MASK, + freq << ADSP2_CLK_SEL_SHIFT); + if (ret) { + adsp_err(dsp, "Failed to set clock rate: %d\n", ret); + return; + } + break; + default: + /* clock is handled by parent codec driver */ + break; + } +} + +int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = dsp->preloaded; + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_preloader_get); + +int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct wm_adsp *dsp = snd_soc_codec_get_drvdata(codec); + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + char preload[32]; + + snprintf(preload, ARRAY_SIZE(preload), "DSP%u Preload", mc->shift); + + dsp->preloaded = ucontrol->value.integer.value[0]; + + if (ucontrol->value.integer.value[0]) + snd_soc_dapm_force_enable_pin(dapm, preload); + else + snd_soc_dapm_disable_pin(dapm, preload); + + snd_soc_dapm_sync(dapm); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_preloader_put); + +static void wm_adsp_stop_watchdog(struct wm_adsp *dsp) +{ + switch (dsp->rev) { + case 0: + case 1: + return; + default: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_WATCHDOG, + ADSP2_WDT_ENA_MASK, 0); + } +} + +int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event, + unsigned int freq) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + struct wm_coeff_ctl *ctl; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + wm_adsp2_set_dspclk(dsp, freq); + queue_work(system_unbound_wq, &dsp->boot_work); + break; + case SND_SOC_DAPM_PRE_PMD: + mutex_lock(&dsp->pwr_lock); + + wm_adsp_debugfs_clear(dsp); + + dsp->fw_id = 0; + dsp->fw_id_version = 0; + + dsp->booted = false; + + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); + + list_for_each_entry(ctl, &dsp->ctl_list, list) + ctl->enabled = 0; + + wm_adsp_free_alg_regions(dsp); + + mutex_unlock(&dsp->pwr_lock); + + adsp_dbg(dsp, "Shutdown complete\n"); + break; + default: + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_early_event); + +int wm_halo_early_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + struct wm_coeff_ctl *ctl; + int ret; + + switch (event) { + case SND_SOC_DAPM_PRE_PMU: + ret = regmap_update_bits(dsp->regmap, + dsp->base + HALO_CCM_CORE_CONTROL, + HALO_CORE_RESET, HALO_CORE_RESET); + if (ret != 0) { + adsp_err(dsp, "Error while resetting core: %d\n", ret); + return ret; + } + + queue_work(system_unbound_wq, &dsp->boot_work); + break; + case SND_SOC_DAPM_PRE_PMD: + mutex_lock(&dsp->pwr_lock); + + wm_adsp_debugfs_clear(dsp); + + dsp->fw_id = 0; + dsp->fw_id_version = 0; + + dsp->booted = false; + + list_for_each_entry(ctl, &dsp->ctl_list, list) + ctl->enabled = 0; + + wm_adsp_free_alg_regions(dsp); + + mutex_unlock(&dsp->pwr_lock); + + adsp_dbg(dsp, "Shutdown complete\n"); + break; + default: + break; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_halo_early_event); + +int wm_adsp2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + flush_work(&dsp->boot_work); + + mutex_lock(&dsp->pwr_lock); + + if (!dsp->booted) { + ret = -EIO; + goto err; + } + + ret = wm_adsp2_ena(dsp); + if (ret != 0) + goto err; + + /* Sync set controls */ + ret = wm_coeff_sync_controls(dsp); + if (ret != 0) + goto err; + + wm_adsp2_lock(dsp, dsp->lock_regions); + + ret = regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_CORE_ENA | ADSP2_START, + ADSP2_CORE_ENA | ADSP2_START); + if (ret != 0) + goto err; + + if (wm_adsp_fw[dsp->fw].num_caps != 0) { + ret = wm_adsp_buffer_init(dsp); + if (ret < 0) + goto err; + } + + dsp->running = true; + + mutex_unlock(&dsp->pwr_lock); + + break; + + case SND_SOC_DAPM_PRE_PMD: + /* Tell the firmware to cleanup */ + wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); + + wm_adsp_stop_watchdog(dsp); + + /* Log firmware state, it can be useful for analysis */ + switch (dsp->rev) { + case 0: + wm_adsp2_show_fw_status(dsp); + break; + default: + wm_adsp2v2_show_fw_status(dsp); + break; + } + + mutex_lock(&dsp->pwr_lock); + + dsp->running = false; + + regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_CORE_ENA | ADSP2_START, 0); + + /* Make sure DMAs are quiesced */ + switch (dsp->rev) { + case 0: + regmap_write(dsp->regmap, + dsp->base + ADSP2_RDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2_WDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2_WDMA_CONFIG_2, 0); + + regmap_update_bits(dsp->regmap, + dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA, 0); + break; + default: + regmap_write(dsp->regmap, + dsp->base + ADSP2_RDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2_WDMA_CONFIG_1, 0); + regmap_write(dsp->regmap, + dsp->base + ADSP2V2_WDMA_CONFIG_2, 0); + break; + } + + if (wm_adsp_fw[dsp->fw].num_caps != 0) + wm_adsp_buffer_free(dsp); + + mutex_unlock(&dsp->pwr_lock); + + adsp_dbg(dsp, "Execution stopped\n"); + break; + + default: + break; + } + + return 0; +err: + regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_SYS_ENA | ADSP2_CORE_ENA | ADSP2_START, 0); + mutex_unlock(&dsp->pwr_lock); + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp2_event); + +int wm_halo_event(struct snd_soc_dapm_widget *w, struct snd_kcontrol *kcontrol, + int event) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + int ret; + + switch (event) { + case SND_SOC_DAPM_POST_PMU: + flush_work(&dsp->boot_work); + + mutex_lock(&dsp->pwr_lock); + + if (!dsp->booted) { + ret = -EIO; + goto err; + } + wm_halo_apply_calibration(w); + /* Sync set controls */ + ret = wm_coeff_sync_controls(dsp); + if (ret != 0) + goto err; + + //wm_halo_apply_calibration(w); + + adsp_dbg(dsp, "Setting RX rates.\n"); + ret = wm_halo_set_rate_block(dsp, HALO_SAMPLE_RATE_RX1, + dsp->n_rx_rates, dsp->rx_rate_cache); + if (ret) { + adsp_err(dsp, "Failed to set RX rates.\n"); + goto err; + } + + adsp_dbg(dsp, "Setting TX rates.\n"); + ret = wm_halo_set_rate_block(dsp, HALO_SAMPLE_RATE_TX1, + dsp->n_tx_rates, dsp->tx_rate_cache); + if (ret) { + adsp_err(dsp, "Failed to set TX rates.\n"); + goto err; + } + + ret = wm_halo_clear_stream_arb(dsp); + if (ret != 0) + goto err; + + /* disable NMI */ + ret = regmap_write(dsp->regmap, dsp->base + + HALO_INTP_CTL_NMI_CONTROL, 0); + if (ret != 0) { + adsp_err(dsp, "Error while disabling NMI: %d\n", ret); + goto err; + } + + ret = wm_halo_configure_mpu(dsp); + if (ret != 0) + goto err; + + ret = regmap_update_bits(dsp->regmap, + dsp->base + HALO_CCM_CORE_CONTROL, + HALO_CORE_EN, HALO_CORE_EN); + + if (ret != 0) + goto err; + + if (wm_adsp_fw[dsp->fw].num_caps != 0) { + ret = wm_adsp_buffer_init(dsp); + if (ret < 0) + goto err; + } + + dsp->running = true; + + mutex_unlock(&dsp->pwr_lock); + + break; + case SND_SOC_DAPM_PRE_PMD: + /* Tell the firmware to cleanup */ + wm_adsp_signal_event_controls(dsp, WM_ADSP_FW_EVENT_SHUTDOWN); + + /* Log firmware state, it can be useful for analysis */ + wm_halo_show_fw_status(dsp); + + mutex_lock(&dsp->pwr_lock); + + dsp->running = false; + + regmap_update_bits(dsp->regmap, + dsp->base + HALO_CCM_CORE_CONTROL, + HALO_CORE_EN, 0); + + wm_halo_clear_stream_arb(dsp); + + if (wm_adsp_fw[dsp->fw].num_caps != 0) + wm_adsp_buffer_free(dsp); + + mutex_unlock(&dsp->pwr_lock); + + adsp_info(dsp, "Execution stopped\n"); + break; + default: + break; + } + + return 0; +err: + mutex_unlock(&dsp->pwr_lock); + regmap_update_bits(dsp->regmap, dsp->base + HALO_CCM_CORE_CONTROL, + HALO_CORE_EN, 0); + return ret; +} +EXPORT_SYMBOL_GPL(wm_halo_event); + +static int wm_coeff_k_put(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + char *p = ucontrol->value.bytes.data; + int ret = 0; + + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { + ret = 0; + } else + memcpy(ctl->cache, p, ctl->len); + + ctl->set = 1; + ret = wm_coeff_write_control(ctl, p, ctl->len); + + + return ret; +} +static int wm_coeff_k_get(struct snd_kcontrol *kctl, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_bytes_ext *bytes_ext = + (struct soc_bytes_ext *)kctl->private_value; + struct wm_coeff_ctl *ctl = bytes_ext_to_ctl(bytes_ext); + char *p = ucontrol->value.bytes.data; + int ret = 0; + + if (ctl->flags & WMFW_CTL_FLAG_VOLATILE) { + ret = wm_coeff_read_control(ctl, p, ctl->len); + } else { + ret = wm_coeff_read_control(ctl, ctl->cache, ctl->len); + memcpy(p, ctl->cache, ctl->len); + } + + return ret; +} +static int wm_adsp_k_ctl_put(struct wm_adsp *dsp, const char *name, int value) +{ + struct snd_kcontrol *kctl = NULL; + struct snd_ctl_elem_value ucontrol; + struct snd_soc_card *card = dsp->codec->component.card; + + kctl = snd_soc_card_get_kcontrol(card, name); + if (kctl == NULL) { + adsp_warn(dsp, "%s: %s isn't found\n", __func__, name); + return -1; + } + + adsp_dbg(dsp, "%s: %s:0x%x\n", __func__, kctl->id.name, value); + value = cpu_to_be32(value); + memcpy((char *)ucontrol.value.bytes.data, (char *)&value, sizeof(value)); + wm_coeff_k_put(kctl, &ucontrol); + + return 0; +} + +static int wm_adsp_k_ctl_get(struct wm_adsp *dsp, const char *name) +{ + struct snd_kcontrol *kctl = NULL; + struct snd_ctl_elem_value ucontrol; + struct snd_soc_card *card = dsp->codec->component.card; + + int value = 0; + + kctl = snd_soc_card_get_kcontrol(card, name); + if (kctl == NULL) { + adsp_warn(dsp, "%s: %s isn't found\n", __func__, name); + return -1; + } + + wm_coeff_k_get(kctl, &ucontrol); + memcpy((char *)&value, (char *)ucontrol.value.bytes.data, sizeof(value)); + value = be32_to_cpu(value); + + adsp_dbg(dsp, "%s: %s:0x%x\n", __func__, kctl->id.name, value); + + return 0; +} + +static int wm_halo_apply_calibration(struct snd_soc_dapm_widget *w) +{ + struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm); + struct wm_adsp *dsps = snd_soc_codec_get_drvdata(codec); + struct wm_adsp *dsp = &dsps[w->shift]; + + switch(dsp->fw) { + case WM_ADSP_FW_CALIB: + adsp_warn(dsp, "Set ambient %d, only for Z Diagnostic\n", dsp->ambient); + wm_adsp_k_ctl_put(dsp, "DSP1X Diag Z cd CAL_AMBIENT", dsp->ambient); + break; + case WM_ADSP_FW_DIAG: + adsp_warn(dsp, "Set ambient %d, only for Diagnostic\n", dsp->ambient); + wm_adsp_k_ctl_put(dsp, "DSP1X Diag cd CAL_AMBIENT", dsp->ambient); + break; + case WM_ADSP_FW_SPK_PROT: + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd CAL_R", dsp->cal_z); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd CAL_STATUS", dsp->cal_status); + wm_adsp_k_ctl_put(dsp, "DSP1X Protection cd CAL_CHECKSUM", dsp->cal_chksum); + wm_adsp_k_ctl_get(dsp, "DSP1X Protection cd CAL_R"); + wm_adsp_k_ctl_get(dsp, "DSP1X Protection cd CAL_STATUS"); + wm_adsp_k_ctl_get(dsp, "DSP1X Protection cd CAL_CHECKSUM"); + break; + default: + break; + } + + adsp_warn(dsp, "Do thing'\n"); + return 0; +} + + +int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec) +{ + struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); + char preload[32]; + + snprintf(preload, ARRAY_SIZE(preload), "DSP%d Preload", dsp->num); + snd_soc_dapm_disable_pin(dapm, preload); + + wm_adsp2_init_debugfs(dsp, codec); + + dsp->codec = codec; + + snd_soc_add_codec_controls(codec, + wm_adsp_cal_controls, + ARRAY_SIZE(wm_adsp_cal_controls)); + + return snd_soc_add_codec_controls(codec, + &wm_adsp_fw_controls[dsp->num - 1], + 1); +} +EXPORT_SYMBOL_GPL(wm_adsp2_codec_probe); + +int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec) +{ + wm_adsp2_cleanup_debugfs(dsp); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_codec_remove); + +int wm_adsp2_init(struct wm_adsp *dsp) +{ + int ret; + + switch (dsp->rev) { + case 0: + /* + * Disable the DSP memory by default when in reset for a small + * power saving. + */ + ret = regmap_update_bits(dsp->regmap, dsp->base + ADSP2_CONTROL, + ADSP2_MEM_ENA, 0); + if (ret) { + adsp_err(dsp, + "Failed to clear memory retention: %d\n", ret); + return ret; + } + break; + default: + break; + } + + INIT_LIST_HEAD(&dsp->alg_regions); + INIT_LIST_HEAD(&dsp->ctl_list); + INIT_WORK(&dsp->boot_work, wm_adsp2_boot_work); + + mutex_init(&dsp->pwr_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_init); + +int wm_halo_init(struct wm_adsp *dsp) +{ + INIT_LIST_HEAD(&dsp->alg_regions); + INIT_LIST_HEAD(&dsp->ctl_list); + INIT_WORK(&dsp->boot_work, wm_halo_boot_work); + + mutex_init(&dsp->pwr_lock); + + dsp->rx_rate_cache = kcalloc(dsp->n_rx_rates, sizeof(u8), GFP_KERNEL); + dsp->tx_rate_cache = kcalloc(dsp->n_tx_rates, sizeof(u8), GFP_KERNEL); + + dsp->ambient = AMBIENT_DEFAULT; + dsp->cal_z = CAL_R_DEFAULT; + dsp->cal_status = CAL_STATUS_DEFAULT; + dsp->cal_chksum = CAL_R_DEFAULT + CAL_STATUS_DEFAULT; + return 0; +} +EXPORT_SYMBOL_GPL(wm_halo_init); + +void wm_adsp2_remove(struct wm_adsp *dsp) +{ + struct wm_coeff_ctl *ctl; + + while (!list_empty(&dsp->ctl_list)) { + ctl = list_first_entry(&dsp->ctl_list, struct wm_coeff_ctl, + list); + list_del(&ctl->list); + wm_adsp_free_ctl_blk(ctl); + } + + kfree(dsp->rx_rate_cache); + kfree(dsp->tx_rate_cache); +} +EXPORT_SYMBOL_GPL(wm_adsp2_remove); + +static inline int wm_adsp_compr_attached(struct wm_adsp_compr *compr) +{ + return compr->buf != NULL; +} + +static int wm_adsp_compr_attach(struct wm_adsp_compr *compr) +{ + /* + * Note this will be more complex once each DSP can support multiple + * streams + */ + if (!compr->dsp->buffer) + return -EINVAL; + + compr->buf = compr->dsp->buffer; + compr->buf->compr = compr; + + return 0; +} + +static void wm_adsp_compr_detach(struct wm_adsp_compr *compr) +{ + if (!compr) + return; + + /* Wake the poll so it can see buffer is no longer attached */ + if (compr->stream) + snd_compr_fragment_elapsed(compr->stream); + + if (wm_adsp_compr_attached(compr)) { + compr->buf->compr = NULL; + compr->buf = NULL; + } +} + +int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream) +{ + struct wm_adsp_compr *compr; + int ret = 0; + + mutex_lock(&dsp->pwr_lock); + + if (wm_adsp_fw[dsp->fw].num_caps == 0) { + adsp_err(dsp, "Firmware does not support compressed API\n"); + ret = -ENXIO; + goto out; + } + + if (wm_adsp_fw[dsp->fw].compr_direction != stream->direction) { + adsp_err(dsp, "Firmware does not support stream direction\n"); + ret = -EINVAL; + goto out; + } + + if (dsp->compr) { + /* It is expect this limitation will be removed in future */ + adsp_err(dsp, "Only a single stream supported per DSP\n"); + ret = -EBUSY; + goto out; + } + + compr = kzalloc(sizeof(*compr), GFP_KERNEL); + if (!compr) { + ret = -ENOMEM; + goto out; + } + + compr->dsp = dsp; + compr->stream = stream; + + dsp->compr = compr; + + stream->runtime->private_data = compr; + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_open); + +int wm_adsp_compr_free(struct snd_compr_stream *stream) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + + mutex_lock(&dsp->pwr_lock); + + wm_adsp_compr_detach(compr); + dsp->compr = NULL; + + kfree(compr->raw_buf); + kfree(compr); + + mutex_unlock(&dsp->pwr_lock); + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_free); + +static int wm_adsp_compr_check_params(struct snd_compr_stream *stream, + struct snd_compr_params *params) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + const struct wm_adsp_fw_caps *caps; + const struct snd_codec_desc *desc; + int i, j; + + if (params->buffer.fragment_size < WM_ADSP_MIN_FRAGMENT_SIZE || + params->buffer.fragment_size > WM_ADSP_MAX_FRAGMENT_SIZE || + params->buffer.fragments < WM_ADSP_MIN_FRAGMENTS || + params->buffer.fragments > WM_ADSP_MAX_FRAGMENTS || + params->buffer.fragment_size % WM_ADSP_DATA_WORD_SIZE) { + adsp_err(dsp, "Invalid buffer fragsize=%d fragments=%d\n", + params->buffer.fragment_size, + params->buffer.fragments); + + return -EINVAL; + } + + for (i = 0; i < wm_adsp_fw[dsp->fw].num_caps; i++) { + caps = &wm_adsp_fw[dsp->fw].caps[i]; + desc = &caps->desc; + + if (caps->id != params->codec.id) + continue; + + if (stream->direction == SND_COMPRESS_PLAYBACK) { + if (desc->max_ch < params->codec.ch_out) + continue; + } else { + if (desc->max_ch < params->codec.ch_in) + continue; + } + + if (!(desc->formats & (1 << params->codec.format))) + continue; + + for (j = 0; j < desc->num_sample_rates; ++j) + if (desc->sample_rates[j] == params->codec.sample_rate) + return 0; + } + + adsp_err(dsp, "Invalid params id=%u ch=%u,%u rate=%u fmt=%u\n", + params->codec.id, params->codec.ch_in, params->codec.ch_out, + params->codec.sample_rate, params->codec.format); + return -EINVAL; +} + +static inline unsigned int wm_adsp_compr_frag_words(struct wm_adsp_compr *compr) +{ + return compr->size.fragment_size / WM_ADSP_DATA_WORD_SIZE; +} + +int wm_adsp_compr_set_params(struct snd_compr_stream *stream, + struct snd_compr_params *params) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + unsigned int size; + int ret; + + ret = wm_adsp_compr_check_params(stream, params); + if (ret) + return ret; + + compr->size = params->buffer; + + adsp_dbg(compr->dsp, "fragment_size=%d fragments=%d\n", + compr->size.fragment_size, compr->size.fragments); + + size = wm_adsp_compr_frag_words(compr) * sizeof(*compr->raw_buf); + compr->raw_buf = kmalloc(size, GFP_DMA | GFP_KERNEL); + if (!compr->raw_buf) + return -ENOMEM; + + compr->sample_rate = params->codec.sample_rate; + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_set_params); + +int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, + struct snd_compr_caps *caps) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + int fw = compr->dsp->fw; + int i; + + if (wm_adsp_fw[fw].caps) { + for (i = 0; i < wm_adsp_fw[fw].num_caps; i++) + caps->codecs[i] = wm_adsp_fw[fw].caps[i].id; + + caps->num_codecs = i; + caps->direction = wm_adsp_fw[fw].compr_direction; + + caps->min_fragment_size = WM_ADSP_MIN_FRAGMENT_SIZE; + caps->max_fragment_size = WM_ADSP_MAX_FRAGMENT_SIZE; + caps->min_fragments = WM_ADSP_MIN_FRAGMENTS; + caps->max_fragments = WM_ADSP_MAX_FRAGMENTS; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_get_caps); + +static int wm_adsp_read_data_block(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, + unsigned int num_words, u32 *data) +{ + struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + unsigned int i, reg; + int ret; + + if (!mem) + return -EINVAL; + + reg = wm_adsp_region_to_reg(dsp, mem, mem_addr); + + ret = wm_adsp2_raw_read(MAXBULK, dsp->regmap, reg, data, + sizeof(*data) * num_words); + if (ret < 0) + return ret; + + for (i = 0; i < num_words; ++i) + data[i] = be32_to_cpu(data[i]) & 0x00ffffffu; + + return 0; +} + +static inline int wm_adsp_read_data_word(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, u32 *data) +{ + return wm_adsp_read_data_block(dsp, mem_type, mem_addr, 1, data); +} + +static int wm_adsp_write_data_word(struct wm_adsp *dsp, int mem_type, + unsigned int mem_addr, u32 data) +{ + struct wm_adsp_region const *mem = wm_adsp_find_region(dsp, mem_type); + unsigned int reg; + + if (!mem) + return -EINVAL; + + reg = wm_adsp_region_to_reg(dsp, mem, mem_addr); + + data = cpu_to_be32(data & 0x00ffffffu); + + return regmap_raw_write(dsp->regmap, reg, &data, sizeof(data)); +} + +static inline int wm_adsp_buffer_read(struct wm_adsp_compr_buf *buf, + unsigned int field_offset, u32 *data) +{ + return wm_adsp_read_data_word(buf->dsp, WMFW_ADSP2_XM, + buf->host_buf_ptr + field_offset, data); +} + +static inline int wm_adsp_buffer_write(struct wm_adsp_compr_buf *buf, + unsigned int field_offset, u32 data) +{ + return wm_adsp_write_data_word(buf->dsp, WMFW_ADSP2_XM, + buf->host_buf_ptr + field_offset, data); +} + +static int wm_adsp_buffer_locate(struct wm_adsp_compr_buf *buf) +{ + struct wm_adsp_alg_region *alg_region; + struct wm_adsp *dsp = buf->dsp; + u32 xmalg, addr, magic; + int i, ret; + + alg_region = wm_adsp_find_alg_region(dsp, WMFW_ADSP2_XM, dsp->fw_id); + xmalg = sizeof(struct wm_adsp_system_config_xm_hdr) / sizeof(__be32); + + addr = alg_region->base + xmalg + ALG_XM_FIELD(magic); + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, &magic); + if (ret < 0) + return ret; + + if (magic != WM_ADSP_ALG_XM_STRUCT_MAGIC) + return -EINVAL; + + addr = alg_region->base + xmalg + ALG_XM_FIELD(host_buf_ptr); + for (i = 0; i < 5; ++i) { + ret = wm_adsp_read_data_word(dsp, WMFW_ADSP2_XM, addr, + &buf->host_buf_ptr); + if (ret < 0) + return ret; + + if (buf->host_buf_ptr) + break; + + usleep_range(1000, 2000); + } + + if (!buf->host_buf_ptr) + return -EIO; + + adsp_dbg(dsp, "host_buf_ptr=%x\n", buf->host_buf_ptr); + + return 0; +} + +static int wm_adsp_buffer_populate(struct wm_adsp_compr_buf *buf) +{ + const struct wm_adsp_fw_caps *caps = wm_adsp_fw[buf->dsp->fw].caps; + struct wm_adsp_buffer_region *region; + u32 offset = 0; + int i, ret; + + for (i = 0; i < caps->num_regions; ++i) { + region = &buf->regions[i]; + + region->offset = offset; + region->mem_type = caps->region_defs[i].mem_type; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].base_offset, + ®ion->base_addr); + if (ret < 0) + return ret; + + ret = wm_adsp_buffer_read(buf, caps->region_defs[i].size_offset, + &offset); + if (ret < 0) + return ret; + + region->cumulative_size = offset; + + adsp_dbg(buf->dsp, + "region=%d type=%d base=%04x off=%04x size=%04x\n", + i, region->mem_type, region->base_addr, + region->offset, region->cumulative_size); + } + + return 0; +} + +static int wm_adsp_buffer_init(struct wm_adsp *dsp) +{ + struct wm_adsp_compr_buf *buf; + int ret; + + buf = kzalloc(sizeof(*buf), GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf->dsp = dsp; + buf->read_index = -1; + buf->irq_count = 0xFFFFFFFF; + + ret = wm_adsp_buffer_locate(buf); + if (ret < 0) { + adsp_err(dsp, "Failed to acquire host buffer: %d\n", ret); + goto err_buffer; + } + + buf->regions = kcalloc(wm_adsp_fw[dsp->fw].caps->num_regions, + sizeof(*buf->regions), GFP_KERNEL); + if (!buf->regions) { + ret = -ENOMEM; + goto err_buffer; + } + + ret = wm_adsp_buffer_populate(buf); + if (ret < 0) { + adsp_err(dsp, "Failed to populate host buffer: %d\n", ret); + goto err_regions; + } + + dsp->buffer = buf; + + return 0; + +err_regions: + kfree(buf->regions); +err_buffer: + kfree(buf); + return ret; +} + +static int wm_adsp_buffer_free(struct wm_adsp *dsp) +{ + if (dsp->buffer) { + wm_adsp_compr_detach(dsp->buffer->compr); + + kfree(dsp->buffer->regions); + kfree(dsp->buffer); + + dsp->buffer = NULL; + } + + return 0; +} + +int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + int ret = 0; + + adsp_dbg(dsp, "Trigger: %d\n", cmd); + + mutex_lock(&dsp->pwr_lock); + + switch (cmd) { + case SNDRV_PCM_TRIGGER_START: + if (wm_adsp_compr_attached(compr)) + break; + + ret = wm_adsp_compr_attach(compr); + if (ret < 0) { + adsp_err(dsp, "Failed to link buffer and stream: %d\n", + ret); + break; + } + + /* Trigger the IRQ at one fragment of data */ + ret = wm_adsp_buffer_write(compr->buf, + HOST_BUFFER_FIELD(high_water_mark), + wm_adsp_compr_frag_words(compr)); + if (ret < 0) { + adsp_err(dsp, "Failed to set high water mark: %d\n", + ret); + break; + } + break; + case SNDRV_PCM_TRIGGER_STOP: + break; + default: + ret = -EINVAL; + break; + } + + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_trigger); + +static inline int wm_adsp_buffer_size(struct wm_adsp_compr_buf *buf) +{ + int last_region = wm_adsp_fw[buf->dsp->fw].caps->num_regions - 1; + + return buf->regions[last_region].cumulative_size; +} + +static int wm_adsp_buffer_update_avail(struct wm_adsp_compr_buf *buf) +{ + u32 next_read_index, next_write_index; + int write_index, read_index, avail; + int ret; + + /* Only sync read index if we haven't already read a valid index */ + if (buf->read_index < 0) { + ret = wm_adsp_buffer_read(buf, + HOST_BUFFER_FIELD(next_read_index), + &next_read_index); + if (ret < 0) + return ret; + + read_index = sign_extend32(next_read_index, 23); + + if (read_index < 0) { + adsp_dbg(buf->dsp, "Avail check on unstarted stream\n"); + return 0; + } + + buf->read_index = read_index; + } + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(next_write_index), + &next_write_index); + if (ret < 0) + return ret; + + write_index = sign_extend32(next_write_index, 23); + + avail = write_index - buf->read_index; + if (avail < 0) + avail += wm_adsp_buffer_size(buf); + + adsp_dbg(buf->dsp, "readindex=0x%x, writeindex=0x%x, avail=%d\n", + buf->read_index, write_index, avail * WM_ADSP_DATA_WORD_SIZE); + + buf->avail = avail; + + return 0; +} + +static int wm_adsp_buffer_get_error(struct wm_adsp_compr_buf *buf) +{ + int ret; + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(error), &buf->error); + if (ret < 0) { + adsp_err(buf->dsp, "Failed to check buffer error: %d\n", ret); + return ret; + } + if (buf->error != 0) { + adsp_err(buf->dsp, "Buffer error occurred: %d\n", buf->error); + return -EIO; + } + + return 0; +} + +int wm_adsp_compr_handle_irq(struct wm_adsp *dsp) +{ + struct wm_adsp_compr_buf *buf; + struct wm_adsp_compr *compr; + int ret = 0; + + mutex_lock(&dsp->pwr_lock); + + buf = dsp->buffer; + compr = dsp->compr; + + if (!buf) { + ret = -ENODEV; + goto out; + } + + adsp_dbg(dsp, "Handling buffer IRQ\n"); + + ret = wm_adsp_buffer_get_error(buf); + if (ret < 0) + goto out_notify; /* Wake poll to report error */ + + ret = wm_adsp_buffer_read(buf, HOST_BUFFER_FIELD(irq_count), + &buf->irq_count); + if (ret < 0) { + adsp_err(dsp, "Failed to get irq_count: %d\n", ret); + goto out; + } + + ret = wm_adsp_buffer_update_avail(buf); + if (ret < 0) { + adsp_err(dsp, "Error reading avail: %d\n", ret); + goto out; + } + + if (wm_adsp_fw[dsp->fw].voice_trigger && buf->irq_count == 2) + ret = WM_ADSP_COMPR_VOICE_TRIGGER; + +out_notify: + if (compr && compr->stream) + snd_compr_fragment_elapsed(compr->stream); + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_handle_irq); + +static int wm_adsp_buffer_reenable_irq(struct wm_adsp_compr_buf *buf) +{ + if (buf->irq_count & 0x01) + return 0; + + adsp_dbg(buf->dsp, "Enable IRQ(0x%x) for next fragment\n", + buf->irq_count); + + buf->irq_count |= 0x01; + + return wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(irq_ack), + buf->irq_count); +} + +int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + struct wm_adsp_compr_buf *buf; + int ret = 0; + + adsp_dbg(dsp, "Pointer request\n"); + + mutex_lock(&dsp->pwr_lock); + + buf = compr->buf; + + if (!compr->buf || compr->buf->error) { + snd_compr_stop_error(stream, SNDRV_PCM_STATE_XRUN); + ret = -EIO; + goto out; + } + + if (buf->avail < wm_adsp_compr_frag_words(compr)) { + ret = wm_adsp_buffer_update_avail(buf); + if (ret < 0) { + adsp_err(dsp, "Error reading avail: %d\n", ret); + goto out; + } + + /* + * If we really have less than 1 fragment available tell the + * DSP to inform us once a whole fragment is available. + */ + if (buf->avail < wm_adsp_compr_frag_words(compr)) { + ret = wm_adsp_buffer_get_error(buf); + if (ret < 0) { + if (compr->buf->error) + snd_compr_stop_error(stream, + SNDRV_PCM_STATE_XRUN); + goto out; + } + + ret = wm_adsp_buffer_reenable_irq(buf); + if (ret < 0) { + adsp_err(dsp, + "Failed to re-enable buffer IRQ: %d\n", + ret); + goto out; + } + } + } + + tstamp->copied_total = compr->copied_total; + tstamp->copied_total += buf->avail * WM_ADSP_DATA_WORD_SIZE; + tstamp->sampling_rate = compr->sample_rate; + +out: + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_pointer); + +static int wm_adsp_buffer_capture_block(struct wm_adsp_compr *compr, int target) +{ + struct wm_adsp_compr_buf *buf = compr->buf; + u8 *pack_in = (u8 *)compr->raw_buf; + u8 *pack_out = (u8 *)compr->raw_buf; + unsigned int adsp_addr; + int mem_type, nwords, max_read; + int i, j, ret; + + /* Calculate read parameters */ + for (i = 0; i < wm_adsp_fw[buf->dsp->fw].caps->num_regions; ++i) + if (buf->read_index < buf->regions[i].cumulative_size) + break; + + if (i == wm_adsp_fw[buf->dsp->fw].caps->num_regions) + return -EINVAL; + + mem_type = buf->regions[i].mem_type; + adsp_addr = buf->regions[i].base_addr + + (buf->read_index - buf->regions[i].offset); + + max_read = wm_adsp_compr_frag_words(compr); + nwords = buf->regions[i].cumulative_size - buf->read_index; + + if (nwords > target) + nwords = target; + if (nwords > buf->avail) + nwords = buf->avail; + if (nwords > max_read) + nwords = max_read; + if (!nwords) + return 0; + + /* Read data from DSP */ + ret = wm_adsp_read_data_block(buf->dsp, mem_type, adsp_addr, + nwords, compr->raw_buf); + if (ret < 0) + return ret; + + /* Remove the padding bytes from the data read from the DSP */ + for (i = 0; i < nwords; i++) { + for (j = 0; j < WM_ADSP_DATA_WORD_SIZE; j++) + *pack_out++ = *pack_in++; + + pack_in += sizeof(*(compr->raw_buf)) - WM_ADSP_DATA_WORD_SIZE; + } + + /* update read index to account for words read */ + buf->read_index += nwords; + if (buf->read_index == wm_adsp_buffer_size(buf)) + buf->read_index = 0; + + ret = wm_adsp_buffer_write(buf, HOST_BUFFER_FIELD(next_read_index), + buf->read_index); + if (ret < 0) + return ret; + + /* update avail to account for words read */ + buf->avail -= nwords; + + return nwords; +} + +static int wm_adsp_compr_read(struct wm_adsp_compr *compr, + char __user *buf, size_t count) +{ + struct wm_adsp *dsp = compr->dsp; + int ntotal = 0; + int nwords, nbytes; + + adsp_dbg(dsp, "Requested read of %zu bytes\n", count); + + if (!compr->buf || compr->buf->error) { + snd_compr_stop_error(compr->stream, SNDRV_PCM_STATE_XRUN); + return -EIO; + } + + count /= WM_ADSP_DATA_WORD_SIZE; + + do { + nwords = wm_adsp_buffer_capture_block(compr, count); + if (nwords < 0) { + adsp_err(dsp, "Failed to capture block: %d\n", nwords); + return nwords; + } + + nbytes = nwords * WM_ADSP_DATA_WORD_SIZE; + + adsp_dbg(dsp, "Read %d bytes\n", nbytes); + + if (copy_to_user(buf + ntotal, compr->raw_buf, nbytes)) { + adsp_err(dsp, "Failed to copy data to user: %d, %d\n", + ntotal, nbytes); + return -EFAULT; + } + + count -= nwords; + ntotal += nbytes; + } while (nwords > 0 && count > 0); + + compr->copied_total += ntotal; + + return ntotal; +} + +int wm_adsp_compr_copy(struct snd_compr_stream *stream, char __user *buf, + size_t count) +{ + struct wm_adsp_compr *compr = stream->runtime->private_data; + struct wm_adsp *dsp = compr->dsp; + int ret; + + mutex_lock(&dsp->pwr_lock); + + if (stream->direction == SND_COMPRESS_CAPTURE) + ret = wm_adsp_compr_read(compr, buf, count); + else + ret = -ENOTSUPP; + + mutex_unlock(&dsp->pwr_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(wm_adsp_compr_copy); + +int wm_adsp2_lock(struct wm_adsp *dsp, unsigned int lock_regions) +{ + struct regmap *regmap = dsp->regmap; + unsigned int code0, code1, lock_reg; + + if (!(lock_regions & WM_ADSP2_REGION_ALL)) + return 0; + + lock_regions &= WM_ADSP2_REGION_ALL; + lock_reg = dsp->base + ADSP2_LOCK_REGION_1_LOCK_REGION_0; + + while (lock_regions) { + code0 = code1 = 0; + if (lock_regions & BIT(0)) { + code0 = ADSP2_LOCK_CODE_0; + code1 = ADSP2_LOCK_CODE_1; + } + if (lock_regions & BIT(1)) { + code0 |= ADSP2_LOCK_CODE_0 << ADSP2_LOCK_REGION_SHIFT; + code1 |= ADSP2_LOCK_CODE_1 << ADSP2_LOCK_REGION_SHIFT; + } + regmap_write(regmap, lock_reg, code0); + regmap_write(regmap, lock_reg, code1); + lock_regions >>= 2; + lock_reg += 2; + } + + return 0; +} +EXPORT_SYMBOL_GPL(wm_adsp2_lock); + +irqreturn_t wm_adsp2_bus_error(struct wm_adsp *dsp) +{ + unsigned int val; + struct regmap *regmap = dsp->regmap; + int ret = 0; + + ret = regmap_read(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, &val); + if (ret) { + adsp_err(dsp, + "Failed to read Region Lock Ctrl register: %d\n", ret); + return IRQ_HANDLED; + } + + if (val & ADSP2_WDT_TIMEOUT_STS_MASK) { + adsp_err(dsp, "watchdog timeout error\n"); + wm_adsp_stop_watchdog(dsp); + } + + if (val & (ADSP2_SLAVE_ERR_MASK | ADSP2_REGION_LOCK_ERR_MASK)) { + if (val & ADSP2_SLAVE_ERR_MASK) + adsp_err(dsp, "bus error: slave error\n"); + else + adsp_err(dsp, "bus error: region lock error\n"); + + ret = regmap_read(regmap, dsp->base + ADSP2_BUS_ERR_ADDR, &val); + if (ret) { + adsp_err(dsp, + "Failed to read Bus Err Addr register: %d\n", + ret); + return IRQ_HANDLED; + } + + adsp_err(dsp, "bus error address = 0x%x\n", + val & ADSP2_BUS_ERR_ADDR_MASK); + + ret = regmap_read(regmap, + dsp->base + ADSP2_PMEM_ERR_ADDR_XMEM_ERR_ADDR, + &val); + if (ret) { + adsp_err(dsp, + "Failed to read Pmem Xmem Err Addr register: %d\n", + ret); + return IRQ_HANDLED; + } + + adsp_err(dsp, "xmem error address = 0x%x\n", + val & ADSP2_XMEM_ERR_ADDR_MASK); + adsp_err(dsp, "pmem error address = 0x%x\n", + (val & ADSP2_PMEM_ERR_ADDR_MASK) >> + ADSP2_PMEM_ERR_ADDR_SHIFT); + } + + regmap_update_bits(regmap, dsp->base + ADSP2_LOCK_REGION_CTRL, + ADSP2_CTRL_ERR_EINT, ADSP2_CTRL_ERR_EINT); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(wm_adsp2_bus_error); + +static void wm_halo_dump_fault_info(struct wm_adsp *dsp, const char *region, + unsigned int addr, unsigned int status) +{ + unsigned int write = status & HALO_MPU_VIO_ERR_WR_MASK; + unsigned int type = (status & HALO_MPU_VIO_STS_MASK) >> + HALO_MPU_VIO_STS_SHIFT; + unsigned int src = (status & HALO_MPU_VIO_ERR_SRC_MASK) >> + HALO_MPU_VIO_ERR_SRC_SHIFT; + + adsp_warn(dsp, "%s: FAULT_ADDR:0x%x FAULT_STATUS:0x%x %s\n", + region, addr, status, + write ? "write" : "read"); + + switch (src) { + case 0: + adsp_warn(dsp, "%s: SRC=HALO\n", region); + break; + default: + adsp_warn(dsp, "%s: SRC=Requestor%u\n", region, src); + break; + } + + adsp_warn(dsp, "%s: %s %s %s %s %s %s\n", + region, + type & HALO_MPU_VIO_SRAM ? "SRAM" : "", + type & HALO_MPU_VIO_REG ? "REG" : "", + type & HALO_MPU_VIO_AHB ? "AHB" : "", + type & HALO_MPU_VIO_EREG ? "EREG" : "", + type & HALO_MPU_VIO_EXTERNAL_MEM ? "ExtMem" : "", + type & HALO_MPU_VIO_NON_EXIST ? "NotExist" : ""); +} + +irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp) +{ + struct regmap *regmap = dsp->regmap; + unsigned int fault[6], ahb_sts, reg; + int ret; + + mutex_lock(&dsp->pwr_lock); + + /* Ensure we log the fault even if we fail to read the fault info */ + adsp_warn(dsp, "MPU FAULT\n"); + + ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_1, + &ahb_sts); + if (ret) { + adsp_warn(dsp, "Failed to read AHB DEBUG_1 (%d)\n", ret); + goto exit_unlock; + } + + adsp_warn(dsp, "AHB WINDOW: ADDR: 0x%x STATUS: 0x%x\n", + (ahb_sts & HALO_AHBM_CORE_ERR_ADDR_MASK) >> + HALO_AHBM_CORE_ERR_ADDR_SHIFT, + ahb_sts); + adsp_warn(dsp, "AHB WINDOW: %s %s %s %s\n", + (ahb_sts & HALO_AHBM_ADDR_ERR_MASK) ? "ADDR" : "", + (ahb_sts & HALO_AHBM_LOCKED_ERR_MASK) ? "LOCKED" : "", + (ahb_sts & HALO_AHBM_SIZE_ERR_MASK) ? "SIZE" : "", + (ahb_sts & HALO_AHBM_MODE_ERR_MASK) ? "MODE" : ""); + + ret = regmap_read(regmap, dsp->base_sysinfo + HALO_AHBM_WINDOW_DEBUG_0, + &ahb_sts); + if (ret) { + adsp_warn(dsp, "Failed to read AHB DEBUG_0 (%d)\n", ret); + goto exit_unlock; + } + + adsp_warn(dsp, "AHB SYS_ADDR: 0x%x\n", ahb_sts); + + ret = regmap_bulk_read(regmap, dsp->base + HALO_MPU_XM_VIO_ADDR, + fault, ARRAY_SIZE(fault)); + if (ret) { + adsp_warn(dsp, "Failed to read MPU fault info (%d)\n", ret); + goto exit_unlock; + } + + wm_halo_dump_fault_info(dsp, "XM", fault[0], fault[1]); + wm_halo_dump_fault_info(dsp, "YM", fault[2], fault[3]); + wm_halo_dump_fault_info(dsp, "PM", fault[4], fault[5]); + + /* Clear fault status */ + for (reg = HALO_MPU_XM_VIO_STATUS; reg <= HALO_MPU_PM_VIO_STATUS; + reg += 8) { + ret = regmap_write(regmap, dsp->base + reg, 0); + if (ret) + adsp_warn(dsp, "Failed to clear MPU status @0x%x (%d)\n", + reg, ret); + } + +exit_unlock: + mutex_unlock(&dsp->pwr_lock); + + return IRQ_HANDLED; +} +EXPORT_SYMBOL_GPL(wm_halo_bus_error); + +MODULE_LICENSE("GPL v2"); diff --git a/techpack/audio/asoc/codecs/cs35l41/wm_adsp.h b/techpack/audio/asoc/codecs/cs35l41/wm_adsp.h new file mode 100644 index 000000000000..084d3aa1e14a --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/wm_adsp.h @@ -0,0 +1,195 @@ +/* + * wm_adsp.h -- Wolfson ADSP support + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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. + */ + +#ifndef __WM_ADSP_H +#define __WM_ADSP_H + +#include +#include +#include + +#include "wmfw.h" + +/* Return values for wm_adsp_compr_handle_irq */ +#define WM_ADSP_COMPR_OK 0 +#define WM_ADSP_COMPR_VOICE_TRIGGER 1 + +#define WM_ADSP2_REGION_0 BIT(0) +#define WM_ADSP2_REGION_1 BIT(1) +#define WM_ADSP2_REGION_2 BIT(2) +#define WM_ADSP2_REGION_3 BIT(3) +#define WM_ADSP2_REGION_4 BIT(4) +#define WM_ADSP2_REGION_5 BIT(5) +#define WM_ADSP2_REGION_6 BIT(6) +#define WM_ADSP2_REGION_7 BIT(7) +#define WM_ADSP2_REGION_8 BIT(8) +#define WM_ADSP2_REGION_9 BIT(9) +#define WM_ADSP2_REGION_1_9 (WM_ADSP2_REGION_1 | \ + WM_ADSP2_REGION_2 | WM_ADSP2_REGION_3 | \ + WM_ADSP2_REGION_4 | WM_ADSP2_REGION_5 | \ + WM_ADSP2_REGION_6 | WM_ADSP2_REGION_7 | \ + WM_ADSP2_REGION_8 | WM_ADSP2_REGION_9) +#define WM_ADSP2_REGION_ALL (WM_ADSP2_REGION_0 | WM_ADSP2_REGION_1_9) + +struct wm_adsp_region { + int type; + unsigned int base; +}; + +struct wm_adsp_alg_region { + struct list_head list; + unsigned int alg; + int type; + unsigned int base; +}; + +struct wm_adsp_compr; +struct wm_adsp_compr_buf; + +struct wm_adsp { + const char *part; + int rev; + int num; + int type; + struct device *dev; + struct regmap *regmap; + struct snd_soc_codec *codec; + int cal_z; + int ambient; + int cal_status; + int cal_chksum; + int block_bypass; + int block_bypass_in_enh; + int base; + int base_sysinfo; + int sysclk_reg; + int sysclk_mask; + int sysclk_shift; + + struct list_head alg_regions; + + unsigned int fw_id; + unsigned int fw_id_version; + unsigned int fw_vendor_id; + + const struct wm_adsp_region *mem; + int num_mems; + + int fw; + int fw_ver; + + bool preloaded; + bool booted; + bool running; + + struct list_head ctl_list; + + struct work_struct boot_work; + + struct wm_adsp_compr *compr; + struct wm_adsp_compr_buf *buffer; + + struct mutex pwr_lock; + + unsigned int lock_regions; + bool unlock_all; + + unsigned int n_rx_rates; + unsigned int n_tx_rates; + + u8 *rx_rate_cache; + u8 *tx_rate_cache; + +#ifdef CONFIG_DEBUG_FS + struct dentry *debugfs_root; + char *wmfw_file_name; + char *bin_file_name; +#endif +}; + +#define WM_ADSP1(wname, num) \ + SND_SOC_DAPM_PGA_E(wname, SND_SOC_NOPM, num, 0, NULL, 0, \ + wm_adsp1_event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD) + +#define WM_ADSP2_PRELOAD_SWITCH(wname, num) \ + SOC_SINGLE_EXT(wname " Preload Switch", SND_SOC_NOPM, num, 1, 0, \ + wm_adsp2_preloader_get, wm_adsp2_preloader_put) + +#define WM_ADSP2(wname, num, event_fn) \ + SND_SOC_DAPM_SPK(wname " Preload", NULL), \ +{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \ + .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ + .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \ + .subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \ +{ .id = snd_soc_dapm_out_drv, .name = wname, \ + .reg = SND_SOC_NOPM, .shift = num, .event = wm_adsp2_event, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } + +#define WM_HALO(wname, num, event_fn) \ + SND_SOC_DAPM_SPK(wname " Preload", NULL), \ +{ .id = snd_soc_dapm_supply, .name = wname " Preloader", \ + .reg = SND_SOC_NOPM, .shift = num, .event = event_fn, \ + .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_PRE_PMD, \ + .subseq = 100, /* Ensure we run after SYSCLK supply widget */ }, \ +{ .id = snd_soc_dapm_out_drv, .name = wname, \ + .reg = SND_SOC_NOPM, .shift = num, .event = wm_halo_event, \ + .event_flags = SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD } + +extern const struct snd_kcontrol_new wm_adsp_fw_controls[]; + +int wm_adsp1_init(struct wm_adsp *dsp); +int wm_adsp2_init(struct wm_adsp *dsp); +void wm_adsp2_remove(struct wm_adsp *dsp); +int wm_adsp2_codec_probe(struct wm_adsp *dsp, struct snd_soc_codec *codec); +int wm_adsp2_codec_remove(struct wm_adsp *dsp, struct snd_soc_codec *codec); +int wm_halo_init(struct wm_adsp *dsp); +int wm_adsp1_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); + +int wm_halo_set_clocking(struct wm_adsp *dsp, unsigned int freq, + struct mutex *rate_lock); + +int wm_adsp2_early_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event, + unsigned int freq); + +int wm_adsp2_lock(struct wm_adsp *adsp, unsigned int regions); +irqreturn_t wm_adsp2_bus_error(struct wm_adsp *adsp); +irqreturn_t wm_halo_bus_error(struct wm_adsp *dsp); + +int wm_adsp2_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); + +int wm_halo_early_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); +int wm_halo_event(struct snd_soc_dapm_widget *w, + struct snd_kcontrol *kcontrol, int event); + +int wm_adsp2_preloader_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); +int wm_adsp2_preloader_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol); + +int wm_adsp_compr_open(struct wm_adsp *dsp, struct snd_compr_stream *stream); +int wm_adsp_compr_free(struct snd_compr_stream *stream); +int wm_adsp_compr_set_params(struct snd_compr_stream *stream, + struct snd_compr_params *params); +int wm_adsp_compr_get_caps(struct snd_compr_stream *stream, + struct snd_compr_caps *caps); +int wm_adsp_compr_trigger(struct snd_compr_stream *stream, int cmd); +int wm_adsp_compr_handle_irq(struct wm_adsp *dsp); +int wm_adsp_compr_pointer(struct snd_compr_stream *stream, + struct snd_compr_tstamp *tstamp); +int wm_adsp_compr_copy(struct snd_compr_stream *stream, + char __user *buf, size_t count); + +#endif diff --git a/techpack/audio/asoc/codecs/cs35l41/wmfw.h b/techpack/audio/asoc/codecs/cs35l41/wmfw.h new file mode 100644 index 000000000000..5e10bb4737af --- /dev/null +++ b/techpack/audio/asoc/codecs/cs35l41/wmfw.h @@ -0,0 +1,201 @@ +/* + * wmfw.h - Wolfson firmware format information + * + * Copyright 2012 Wolfson Microelectronics plc + * + * Author: Mark Brown + * + * 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. + */ + +#ifndef __WMFW_H +#define __WMFW_H + +#include + +#define WMFW_MAX_ALG_NAME 256 +#define WMFW_MAX_ALG_DESCR_NAME 256 + +#define WMFW_MAX_COEFF_NAME 256 +#define WMFW_MAX_COEFF_DESCR_NAME 256 + +#define WMFW_CTL_FLAG_SYS 0x8000 +#define WMFW_CTL_FLAG_VOLATILE 0x0004 +#define WMFW_CTL_FLAG_WRITEABLE 0x0002 +#define WMFW_CTL_FLAG_READABLE 0x0001 + +/* Non-ALSA coefficient types start at 0x1000 */ +#define WMFW_CTL_TYPE_ACKED 0x1000 /* acked control */ +#define WMFW_CTL_TYPE_HOSTEVENT 0x1001 /* event control */ + +struct wmfw_header { + char magic[4]; + __le32 len; + __le16 rev; + u8 core; + u8 ver; +} __packed; + +struct wmfw_footer { + __le64 timestamp; + __le32 checksum; +} __packed; + +struct wmfw_adsp1_sizes { + __le32 dm; + __le32 pm; + __le32 zm; +} __packed; + +struct wmfw_adsp2_sizes { + __le32 xm; + __le32 ym; + __le32 pm; + __le32 zm; +} __packed; + +struct wmfw_region { + union { + __be32 type; + __le32 offset; + }; + __le32 len; + u8 data[]; +} __packed; + +struct wmfw_id_hdr { + __be32 core_id; + __be32 core_rev; + __be32 id; + __be32 ver; +} __packed; + +struct wmfw_adsp1_id_hdr { + struct wmfw_id_hdr fw; + __be32 zm; + __be32 dm; + __be32 n_algs; +} __packed; + +struct wmfw_adsp2_id_hdr { + struct wmfw_id_hdr fw; + __be32 zm; + __be32 xm; + __be32 ym; + __be32 n_algs; +} __packed; + +struct wmfw_halo_fwid_hdr { + __be32 core_id; + __be32 block_rev; + __be32 vendor_id; + __be32 id; + __be32 ver; +} __packed; + +struct wmfw_halo_id_hdr { + struct wmfw_halo_fwid_hdr fw; + __be32 xm_base; + __be32 xm_size; + __be32 ym_base; + __be32 ym_size; + __be32 n_algs; +} __packed; + +struct wmfw_alg_hdr { + __be32 id; + __be32 ver; +} __packed; + +struct wmfw_adsp1_alg_hdr { + struct wmfw_alg_hdr alg; + __be32 zm; + __be32 dm; +} __packed; + +struct wmfw_adsp2_alg_hdr { + struct wmfw_alg_hdr alg; + __be32 zm; + __be32 xm; + __be32 ym; +} __packed; + +struct wmfw_halo_alg_hdr { + struct wmfw_alg_hdr alg; + __be32 xm_base; + __be32 xm_size; + __be32 ym_base; + __be32 ym_size; +} __packed; + +struct wmfw_adsp_alg_data { + __le32 id; + u8 name[WMFW_MAX_ALG_NAME]; + u8 descr[WMFW_MAX_ALG_DESCR_NAME]; + __le32 ncoeff; + u8 data[]; +} __packed; + +struct wmfw_adsp_coeff_data { + struct { + __le16 offset; + __le16 type; + __le32 size; + } hdr; + u8 name[WMFW_MAX_COEFF_NAME]; + u8 descr[WMFW_MAX_COEFF_DESCR_NAME]; + __le16 ctl_type; + __le16 flags; + __le32 len; + u8 data[]; +} __packed; + +struct wmfw_coeff_hdr { + u8 magic[4]; + __le32 len; + union { + __be32 rev; + __le32 ver; + }; + union { + __be32 core; + __le32 core_ver; + }; + u8 data[]; +} __packed; + +struct wmfw_coeff_item { + __le16 offset; + __le16 type; + __le32 id; + __le32 ver; + __le32 sr; + __le32 len; + u8 data[]; +} __packed; + +#define WMFW_ADSP1 1 +#define WMFW_ADSP2 2 +#define WMFW_HALO 4 + +#define WMFW_ABSOLUTE 0xf0 +#define WMFW_ALGORITHM_DATA 0xf2 +#define WMFW_NAME_TEXT 0xfe +#define WMFW_INFO_TEXT 0xff + +#define WMFW_ADSP1_PM 2 +#define WMFW_ADSP1_DM 3 +#define WMFW_ADSP1_ZM 4 + +#define WMFW_ADSP2_PM 2 +#define WMFW_ADSP2_ZM 4 +#define WMFW_ADSP2_XM 5 +#define WMFW_ADSP2_YM 6 + +#define WMFW_HALO_PM_PACKED 0x10 +#define WMFW_HALO_XM_PACKED 0x11 +#define WMFW_HALO_YM_PACKED 0x12 + +#endif diff --git a/techpack/audio/asoc/codecs/csra66x0/Kbuild b/techpack/audio/asoc/codecs/csra66x0/Kbuild index 4b1a3ba1a715..0627fc739504 100644 --- a/techpack/audio/asoc/codecs/csra66x0/Kbuild +++ b/techpack/audio/asoc/codecs/csra66x0/Kbuild @@ -104,6 +104,3 @@ endif # Module information used by KBuild framework obj-$(CONFIG_SND_SOC_CSRA66X0) += csra66x0_dlkm.o csra66x0_dlkm-y := $(CSRA66X0_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/ep92/Android.mk b/techpack/audio/asoc/codecs/ep92/Android.mk deleted file mode 100644 index c2ac0599f7d8..000000000000 --- a/techpack/audio/asoc/codecs/ep92/Android.mk +++ /dev/null @@ -1,50 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,qcs405),true) -AUDIO_SELECT := CONFIG_SND_SOC_QCS405=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,qcs405),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=ep92_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_ep92.ko -LOCAL_MODULE_KBUILD_NAME := ep92_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/ep92/Kbuild b/techpack/audio/asoc/codecs/ep92/Kbuild index af1fd083662c..d06b45bd0816 100644 --- a/techpack/audio/asoc/codecs/ep92/Kbuild +++ b/techpack/audio/asoc/codecs/ep92/Kbuild @@ -105,6 +105,3 @@ endif # Module information used by KBuild framework obj-$(CONFIG_SND_SOC_EP92) += ep92_dlkm.o ep92_dlkm-y := $(EP92_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/msm_sdw/Android.mk b/techpack/audio/asoc/codecs/msm_sdw/Android.mk deleted file mode 100644 index 7ec659200c94..000000000000 --- a/techpack/audio/asoc/codecs/msm_sdw/Android.mk +++ /dev/null @@ -1,46 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=msm_sdw_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_msm_sdw.ko -LOCAL_MODULE_KBUILD_NAME := msm_sdw_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/msm_sdw/Kbuild b/techpack/audio/asoc/codecs/msm_sdw/Kbuild index 73db130cb46c..10ef84729221 100644 --- a/techpack/audio/asoc/codecs/msm_sdw/Kbuild +++ b/techpack/audio/asoc/codecs/msm_sdw/Kbuild @@ -114,6 +114,3 @@ endif # Module information used by KBuild framework obj-$(CONFIG_SND_SOC_MSM_SDW) += msm_sdw_dlkm.o msm_sdw_dlkm-y := $(MSM_SDW_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/sdm660_cdc/Android.mk b/techpack/audio/asoc/codecs/sdm660_cdc/Android.mk deleted file mode 100644 index 41f3cc7bc81f..000000000000 --- a/techpack/audio/asoc/codecs/sdm660_cdc/Android.mk +++ /dev/null @@ -1,53 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=analog_cdc_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_analog_cdc.ko -LOCAL_MODULE_KBUILD_NAME := analog_cdc_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_digital_cdc.ko -LOCAL_MODULE_KBUILD_NAME := digital_cdc_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/sdm660_cdc/Kbuild b/techpack/audio/asoc/codecs/sdm660_cdc/Kbuild index de76fab2c027..9bd6630fb7cd 100644 --- a/techpack/audio/asoc/codecs/sdm660_cdc/Kbuild +++ b/techpack/audio/asoc/codecs/sdm660_cdc/Kbuild @@ -120,6 +120,3 @@ analog_cdc_dlkm-y := $(ANALOG_CDC_OBJS) obj-$(CONFIG_SND_SOC_DIGITAL_CDC) += digital_cdc_dlkm.o digital_cdc_dlkm-y := $(DIGITAL_CDC_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/tas2557/Kbuild b/techpack/audio/asoc/codecs/tas2557/Kbuild new file mode 100644 index 000000000000..2215081edeb1 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/Kbuild @@ -0,0 +1,115 @@ +# We can build either as part of a standalone Kernel build or as +# an external module. Determine which mechanism is being used +ifeq ($(MODNAME),) + KERNEL_BUILD := 1 +else + KERNEL_BUILD := 0 +endif + + + +ifeq ($(KERNEL_BUILD), 1) + # These are configurable via Kconfig for kernel-based builds + # Need to explicitly configure for Android-based builds + AUDIO_BLD_DIR := $(ANDROID_BUILD_TOP)/kernel/msm-4.14 + AUDIO_ROOT := $(AUDIO_BLD_DIR)/techpack/audio +endif + +ifeq ($(KERNEL_BUILD), 0) + ifeq ($(CONFIG_ARCH_SM8150), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + ifeq ($(CONFIG_ARCH_SM6150), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif + + ifeq ($(CONFIG_ARCH_SDMSHRIKE), y) + include $(AUDIO_ROOT)/config/sm8150auto.conf + export + INCS += -include $(AUDIO_ROOT)/config/sm8150autoconf.h + endif +endif + +# As per target team, build is done as follows: +# Defconfig : build with default flags +# Slub : defconfig + CONFIG_SLUB_DEBUG := y + +# CONFIG_SLUB_DEBUG_ON := y + CONFIG_PAGE_POISONING := y +# Perf : Using appropriate msmXXXX-perf_defconfig +# +# Shipment builds (user variants) should not have any debug feature +# enabled. This is identified using 'TARGET_BUILD_VARIANT'. Slub builds +# are identified using the CONFIG_SLUB_DEBUG_ON configuration. Since +# there is no other way to identify defconfig builds, QTI internal +# representation of perf builds (identified using the string 'perf'), +# is used to identify if the build is a slub or defconfig one. This +# way no critical debug feature will be enabled for perf and shipment +# builds. Other OEMs are also protected using the TARGET_BUILD_VARIANT +# config. + +############ UAPI ############ +UAPI_DIR := uapi +UAPI_INC := -I$(AUDIO_ROOT)/include/$(UAPI_DIR) + +############ COMMON ############ +COMMON_DIR := include +COMMON_INC := -I$(AUDIO_ROOT)/$(COMMON_DIR) + +############ CS35L41 ############ + +# for CS35L41 Codec +ifdef CONFIG_SND_SOC_TAS2557 + TAS2557_OBJS += tas2557-core.o + TAS2557_OBJS += tas2557-misc.o + TAS2557_OBJS += tas2557-codec.o + TAS2557_OBJS += tas2557-regmap.o + TAS2557_OBJS += tiload.o +endif + +LINUX_INC += -Iinclude/linux + +INCS += $(COMMON_INC) \ + $(UAPI_INC) + +EXTRA_CFLAGS += $(INCS) + + +CDEFINES += -DANI_LITTLE_BYTE_ENDIAN \ + -DANI_LITTLE_BIT_ENDIAN \ + -DDOT11F_LITTLE_ENDIAN_HOST \ + -DANI_COMPILER_TYPE_GCC \ + -DANI_OS_TYPE_ANDROID=6 \ + -DPTT_SOCK_SVC_ENABLE \ + -Wall\ + -Werror\ + -D__linux__ + +KBUILD_CPPFLAGS += $(CDEFINES) + +# Currently, for versions of gcc which support it, the kernel Makefile +# is disabling the maybe-uninitialized warning. Re-enable it for the +# AUDIO driver. Note that we must use EXTRA_CFLAGS here so that it +# will override the kernel settings. +ifeq ($(call cc-option-yn, -Wmaybe-uninitialized),y) +EXTRA_CFLAGS += -Wmaybe-uninitialized +endif +#EXTRA_CFLAGS += -Wmissing-prototypes + +ifeq ($(call cc-option-yn, -Wheader-guard),y) +EXTRA_CFLAGS += -Wheader-guard +endif + +ifeq ($(KERNEL_BUILD), 0) +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/ipc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/dsp/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/asoc/codecs/Module.symvers +KBUILD_EXTRA_SYMBOLS +=$(OUT)/obj/vendor/qcom/opensource/audio-kernel/soc/Module.symvers +endif + +# Module information used by KBuild framework +obj-$(CONFIG_SND_SOC_TAS2557) += tas2557_dlkm.o +tas2557_dlkm-y := $(TAS2557_OBJS) diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557-codec.c b/techpack/audio/asoc/codecs/tas2557/tas2557-codec.c new file mode 100755 index 000000000000..06de3fd7bc43 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557-codec.c @@ -0,0 +1,668 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557-codec.c +** +** Description: +** ALSA SoC driver for Texas Instruments TAS2557 High Performance 4W Smart Amplifier +** +** ============================================================================= +*/ + +#ifdef CONFIG_TAS2557_CODEC + +#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 "tas2557-core.h" +#include "tas2557-codec.h" + +#define KCONTROL_CODEC + +static unsigned int tas2557_codec_read(struct snd_soc_codec *pCodec, + unsigned int nRegister) +{ + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + int ret = 0; + unsigned int Value = 0; + + mutex_lock(&pTAS2557->codec_lock); + + ret = pTAS2557->read(pTAS2557, nRegister, &Value); + if (ret < 0) + dev_err(pTAS2557->dev, "%s, %d, ERROR happen=%d\n", __func__, + __LINE__, ret); + else + ret = Value; + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static int tas2557_codec_write(struct snd_soc_codec *pCodec, unsigned int nRegister, + unsigned int nValue) +{ + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + int ret = 0; + + mutex_lock(&pTAS2557->codec_lock); + + ret = pTAS2557->write(pTAS2557, nRegister, nValue); + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static int tas2557_codec_suspend(struct snd_soc_codec *pCodec) +{ + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + int ret = 0; + + mutex_lock(&pTAS2557->codec_lock); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + pTAS2557->runtime_suspend(pTAS2557); + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static int tas2557_codec_resume(struct snd_soc_codec *pCodec) +{ + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + int ret = 0; + + mutex_lock(&pTAS2557->codec_lock); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + pTAS2557->runtime_resume(pTAS2557); + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static const struct snd_soc_dapm_widget tas2557_dapm_widgets[] = { + SND_SOC_DAPM_AIF_IN("ASI1", "ASI1 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("ASI2", "ASI2 Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_AIF_IN("ASIM", "ASIM Playback", 0, SND_SOC_NOPM, 0, 0), + SND_SOC_DAPM_DAC("DAC", NULL, SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_OUT_DRV("ClassD", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_SUPPLY("PLL", SND_SOC_NOPM, 0, 0, NULL, 0), + SND_SOC_DAPM_SUPPLY("NDivider", SND_SOC_NOPM, 0, 0, NULL, 0), + + SND_SOC_DAPM_OUTPUT("OUT") +}; + +static const struct snd_soc_dapm_route tas2557_audio_map[] = { + {"DAC", NULL, "ASI1"}, + {"DAC", NULL, "ASI2"}, + {"DAC", NULL, "ASIM"}, + {"ClassD", NULL, "DAC"}, + {"OUT", NULL, "ClassD"}, + {"DAC", NULL, "PLL"}, + {"DAC", NULL, "NDivider"}, +}; + +static int tas2557_startup(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + return 0; +} + +static void tas2557_shutdown(struct snd_pcm_substream *substream, + struct snd_soc_dai *dai) +{ + struct snd_soc_codec *codec = dai->codec; + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); +} + +static int tas2557_mute(struct snd_soc_dai *dai, int mute) +{ + struct snd_soc_codec *codec = dai->codec; + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + mutex_lock(&pTAS2557->codec_lock); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + tas2557_enable(pTAS2557, !mute); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_set_dai_sysclk(struct snd_soc_dai *pDAI, + int nClkID, unsigned int nFreqency, int nDir) +{ + struct snd_soc_codec *pCodec = pDAI->codec; + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + + dev_dbg(pTAS2557->dev, "tas2557_set_dai_sysclk: freq = %u\n", nFreqency); + + return 0; +} + +static int tas2557_hw_params(struct snd_pcm_substream *pSubstream, + struct snd_pcm_hw_params *pParams, struct snd_soc_dai *pDAI) +{ + struct snd_soc_codec *pCodec = pDAI->codec; + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + + mutex_lock(&pTAS2557->codec_lock); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); +/* do bit rate setting during platform data */ +/* tas2557_set_bit_rate(pTAS2557, channel_both, snd_pcm_format_width(params_format(pParams))); */ + tas2557_set_sampling_rate(pTAS2557, params_rate(pParams)); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_set_dai_fmt(struct snd_soc_dai *pDAI, unsigned int nFormat) +{ + struct snd_soc_codec *codec = pDAI->codec; + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + return 0; +} + +static int tas2557_prepare(struct snd_pcm_substream *pSubstream, + struct snd_soc_dai *pDAI) +{ + struct snd_soc_codec *codec = pDAI->codec; + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + return 0; +} + +static int tas2557_set_bias_level(struct snd_soc_codec *pCodec, + enum snd_soc_bias_level eLevel) +{ + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + + dev_dbg(pTAS2557->dev, "%s: %d\n", __func__, eLevel); + return 0; +} + +static int tas2557_codec_probe(struct snd_soc_codec *pCodec) +{ + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(pCodec); + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + return 0; +} + +static int tas2557_codec_remove(struct snd_soc_codec *pCodec) +{ + return 0; +} +static int tas2557_mute_ctrl_get(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + mutex_lock(&pTAS2557->codec_lock); + + pValue->value.integer.value[0] = pTAS2557->mbMute; + dev_dbg(pTAS2557->dev, "tas2557_mute_ctrl_get = %d\n", + pTAS2557->mbMute); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_mute_ctrl_put(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + int mbMute = pValue->value.integer.value[0]; + + mutex_lock(&pTAS2557->codec_lock); + + dev_dbg(pTAS2557->dev, "tas2557_mute_ctrl_put = %d\n", mbMute); + + tas2557_permanent_mute(pTAS2557, mbMute); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_power_ctrl_get(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + mutex_lock(&pTAS2557->codec_lock); + + pValue->value.integer.value[0] = pTAS2557->mbPowerUp; + dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_get = %d\n", + pTAS2557->mbPowerUp); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_power_ctrl_put(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + int nPowerOn = pValue->value.integer.value[0]; + + mutex_lock(&pTAS2557->codec_lock); + + dev_dbg(pTAS2557->dev, "tas2557_power_ctrl_put = %d\n", nPowerOn); + tas2557_enable(pTAS2557, (nPowerOn != 0)); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int vendor_id_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = VENDOR_ID_NONE; + + if (pTAS2557->spk_id_gpio_p) + ucontrol->value.integer.value[0] = spk_id_get(pTAS2557->spk_id_gpio_p); + + return 0; +} + +static int pa_version_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = 0; + + if (pTAS2557->mnPGID == TAS2557_PG_VERSION_1P0) + ucontrol->value.integer.value[0] = 1; + else if(pTAS2557->mnPGID == TAS2557_PG_VERSION_2P0) + ucontrol->value.integer.value[0] = 2; + else if(pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) + ucontrol->value.integer.value[0] = 3; + return 0; +} + +static int tas2557_fs_get(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + int nFS = 48000; + + mutex_lock(&pTAS2557->codec_lock); + + if (pTAS2557->mpFirmware->mnConfigurations) + nFS = pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration].mnSamplingRate; + pValue->value.integer.value[0] = nFS; + dev_dbg(pTAS2557->dev, "tas2557_fs_get = %d\n", nFS); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_fs_put(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + int ret = 0; + int nFS = pValue->value.integer.value[0]; + + mutex_lock(&pTAS2557->codec_lock); + + dev_info(pTAS2557->dev, "tas2557_fs_put = %d\n", nFS); + ret = tas2557_set_sampling_rate(pTAS2557, nFS); + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static int tas2557_Cali_get(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + bool ret = 0; + int prm_r0 = 0; + + mutex_lock(&pTAS2557->codec_lock); + + ret = tas2557_get_Cali_prm_r0(pTAS2557, &prm_r0); + if (ret) + pValue->value.integer.value[0] = prm_r0; + + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_program_get(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + mutex_lock(&pTAS2557->codec_lock); + + pValue->value.integer.value[0] = pTAS2557->mnCurrentProgram; + dev_dbg(pTAS2557->dev, "tas2557_program_get = %d\n", + pTAS2557->mnCurrentProgram); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_program_put(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + unsigned int nProgram = pValue->value.integer.value[0]; + int ret = 0, nConfiguration = -1; + + mutex_lock(&pTAS2557->codec_lock); + + if (nProgram == pTAS2557->mnCurrentProgram) + nConfiguration = pTAS2557->mnCurrentConfiguration; + ret = tas2557_set_program(pTAS2557, nProgram, nConfiguration); + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static int tas2557_configuration_get(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + mutex_lock(&pTAS2557->codec_lock); + + pValue->value.integer.value[0] = pTAS2557->mnCurrentConfiguration; + dev_dbg(pTAS2557->dev, "tas2557_configuration_get = %d\n", + pTAS2557->mnCurrentConfiguration); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_configuration_put(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + unsigned int nConfiguration = pValue->value.integer.value[0]; + int ret = 0; + + mutex_lock(&pTAS2557->codec_lock); + + dev_info(pTAS2557->dev, "%s = %d\n", __func__, nConfiguration); + ret = tas2557_set_config(pTAS2557, nConfiguration); + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static int tas2557_calibration_get(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + + mutex_lock(&pTAS2557->codec_lock); + + pValue->value.integer.value[0] = pTAS2557->mnCurrentCalibration; + dev_info(pTAS2557->dev, + "tas2557_calibration_get = %d\n", + pTAS2557->mnCurrentCalibration); + + mutex_unlock(&pTAS2557->codec_lock); + return 0; +} + +static int tas2557_calibration_put(struct snd_kcontrol *pKcontrol, + struct snd_ctl_elem_value *pValue) +{ +#ifdef KCONTROL_CODEC + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(pKcontrol); +#else + struct snd_soc_codec *codec = snd_kcontrol_chip(pKcontrol); +#endif + struct tas2557_priv *pTAS2557 = snd_soc_codec_get_drvdata(codec); + unsigned int nCalibration = pValue->value.integer.value[0]; + int ret = 0; + + mutex_lock(&pTAS2557->codec_lock); + + ret = tas2557_set_calibration(pTAS2557, nCalibration); + + mutex_unlock(&pTAS2557->codec_lock); + return ret; +} + +static const char *const vendor_id_text[] = {"None", "AAC", "SSI", "GOER", "Unknown"}; +static const struct soc_enum vendor_id[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(vendor_id_text), vendor_id_text), +}; + +static const char *const pa_version_text[] = {"Unknown", "tas2557_v1.0", "tas2557_v2.0", "tas2557_v2.1"}; +static const struct soc_enum pa_version[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(pa_version_text), pa_version_text), +}; + +static const struct snd_kcontrol_new tas2557_snd_controls[] = { + SOC_SINGLE_EXT("PowerCtrl", SND_SOC_NOPM, 0, 0x0001, 0, + tas2557_power_ctrl_get, tas2557_power_ctrl_put), + SOC_SINGLE_EXT("Program", SND_SOC_NOPM, 0, 0x00FF, 0, tas2557_program_get, + tas2557_program_put), + SOC_SINGLE_EXT("Configuration", SND_SOC_NOPM, 0, 0x00FF, 0, + tas2557_configuration_get, tas2557_configuration_put), + SOC_SINGLE_EXT("FS", SND_SOC_NOPM, 8000, 48000, 0, + tas2557_fs_get, tas2557_fs_put), + SOC_SINGLE_EXT("Get Cali_Re", SND_SOC_NOPM, 0, 0x7f000000, 0, + tas2557_Cali_get, NULL), + SOC_SINGLE_EXT("Calibration", SND_SOC_NOPM, 0, 0x00FF, 0, + tas2557_calibration_get, tas2557_calibration_put), + SOC_ENUM_EXT("SPK ID", vendor_id, vendor_id_get, NULL), + SOC_ENUM_EXT("SmartPA Version", pa_version, pa_version_get, NULL), + SOC_SINGLE_EXT("SmartPA Mute", SND_SOC_NOPM, 0, 0x0001, 0, + tas2557_mute_ctrl_get, tas2557_mute_ctrl_put), + +}; + +static struct snd_soc_codec_driver soc_codec_driver_tas2557 = { + .probe = tas2557_codec_probe, + .remove = tas2557_codec_remove, + .read = tas2557_codec_read, + .write = tas2557_codec_write, + .suspend = tas2557_codec_suspend, + .resume = tas2557_codec_resume, + .set_bias_level = tas2557_set_bias_level, + .idle_bias_off = true, + .component_driver = { + .controls = tas2557_snd_controls, + .num_controls = ARRAY_SIZE(tas2557_snd_controls), + .dapm_widgets = tas2557_dapm_widgets, + .num_dapm_widgets = ARRAY_SIZE(tas2557_dapm_widgets), + .dapm_routes = tas2557_audio_map, + .num_dapm_routes = ARRAY_SIZE(tas2557_audio_map), + }, +}; + +static struct snd_soc_dai_ops tas2557_dai_ops = { + .startup = tas2557_startup, + .shutdown = tas2557_shutdown, + .digital_mute = tas2557_mute, + .hw_params = tas2557_hw_params, + .prepare = tas2557_prepare, + .set_sysclk = tas2557_set_dai_sysclk, + .set_fmt = tas2557_set_dai_fmt, +}; + +#define TAS2557_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE) +static struct snd_soc_dai_driver tas2557_dai_driver[] = { + { + .name = "tas2557 ASI1", + .id = 0, + .playback = { + .stream_name = "ASI1 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = TAS2557_FORMATS, + }, + .ops = &tas2557_dai_ops, + .symmetric_rates = 1, + }, + { + .name = "tas2557 ASI2", + .id = 1, + .playback = { + .stream_name = "ASI2 Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = TAS2557_FORMATS, + }, + .ops = &tas2557_dai_ops, + .symmetric_rates = 1, + }, + { + .name = "tas2557 ASIM", + .id = 2, + .playback = { + .stream_name = "ASIM Playback", + .channels_min = 2, + .channels_max = 2, + .rates = SNDRV_PCM_RATE_8000_192000, + .formats = TAS2557_FORMATS, + }, + .ops = &tas2557_dai_ops, + .symmetric_rates = 1, + }, +}; + +int tas2557_register_codec(struct tas2557_priv *pTAS2557) +{ + int nResult = 0; + + dev_info(pTAS2557->dev, "%s, enter\n", __func__); + nResult = snd_soc_register_codec(pTAS2557->dev, + &soc_codec_driver_tas2557, + tas2557_dai_driver, ARRAY_SIZE(tas2557_dai_driver)); + return nResult; +} + +int tas2557_deregister_codec(struct tas2557_priv *pTAS2557) +{ + snd_soc_unregister_codec(pTAS2557->dev); + return 0; +} + +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("TAS2557 ALSA SOC Smart Amplifier driver"); +MODULE_LICENSE("GPL v2"); +#endif diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557-codec.h b/techpack/audio/asoc/codecs/tas2557/tas2557-codec.h new file mode 100644 index 000000000000..8e20270c6b92 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557-codec.h @@ -0,0 +1,30 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557-codec.h +** +** Description: +** header file for tas2557-codec.c +** +** ============================================================================= +*/ + +#ifndef _TAS2557_CODEC_H +#define _TAS2557_CODEC_H + +#include "tas2557.h" + +int tas2557_register_codec(struct tas2557_priv *pTAS2557); +int tas2557_deregister_codec(struct tas2557_priv *pTAS2557); + +#endif /* _TAS2557_CODEC_H */ diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557-core.c b/techpack/audio/asoc/codecs/tas2557/tas2557-core.c new file mode 100755 index 000000000000..cc385b2cdaa4 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557-core.c @@ -0,0 +1,2137 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557-core.c +** +** Description: +** TAS2557 common functions for Android Linux +** +** ============================================================================= +*/ + +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas2557.h" +#include "tas2557-core.h" + +#define PPC_DRIVER_CRCCHK 0x00000200 +#define PPC_DRIVER_CONFDEV 0x00000300 +#define PPC_DRIVER_MTPLLSRC 0x00000400 +#define PPC_DRIVER_CFGDEV_NONCRC 0x00000101 + +#define TAS2557_CAL_NAME "/mnt/vendor/persist/audio/tas2557_cal.bin" +#define RESTART_MAX 3 + + +static int tas2557_load_calibration(struct tas2557_priv *pTAS2557, + char *pFileName); +static int tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData *pData, + unsigned int nType); +static void tas2557_clear_firmware(struct TFirmware *pFirmware); +static int tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock *pBlock); +static int tas2557_load_configuration(struct tas2557_priv *pTAS2557, + unsigned int nConfiguration, bool bLoadSame); + +#define TAS2557_UDELAY 0xFFFFFFFE +#define TAS2557_MDELAY 0xFFFFFFFD + +#define TAS2557_BLOCK_PLL 0x00 +#define TAS2557_BLOCK_PGM_ALL 0x0d +#define TAS2557_BLOCK_PGM_DEV_A 0x01 +#define TAS2557_BLOCK_PGM_DEV_B 0x08 +#define TAS2557_BLOCK_CFG_COEFF_DEV_A 0x03 +#define TAS2557_BLOCK_CFG_COEFF_DEV_B 0x0a +#define TAS2557_BLOCK_CFG_PRE_DEV_A 0x04 +#define TAS2557_BLOCK_CFG_PRE_DEV_B 0x0b +#define TAS2557_BLOCK_CFG_POST 0x05 +#define TAS2557_BLOCK_CFG_POST_POWER 0x06 + +static unsigned int p_tas2557_default_data[] = { + TAS2557_SAR_ADC2_REG, 0x05, /* enable SAR ADC */ + TAS2557_CLK_ERR_CTRL2, 0x21, /*clk1:clock hysteresis, 0.34ms; clock halt, 22ms*/ + TAS2557_CLK_ERR_CTRL3, 0x21, /*clk2: rampDown 15dB/us, clock hysteresis, 10.66us; clock halt, 22ms */ + TAS2557_SAFE_GUARD_REG, TAS2557_SAFE_GUARD_PATTERN, /* safe guard */ + 0xFFFFFFFF, 0xFFFFFFFF +}; + +static unsigned int p_tas2557_irq_config[] = { + TAS2557_CLK_HALT_REG, 0x71, /* enable clk halt detect2 interrupt */ + TAS2557_INT_GEN1_REG, 0x11, /* enable spk OC and OV */ + TAS2557_INT_GEN2_REG, 0x11, /* enable clk err1 and die OT */ + TAS2557_INT_GEN3_REG, 0x11, /* enable clk err2 and brownout */ + TAS2557_INT_GEN4_REG, 0x01, /* disable SAR, enable clk halt */ + TAS2557_GPIO4_PIN_REG, 0x07, /* set GPIO4 as int1, default */ + TAS2557_INT_MODE_REG, 0x80, /* active high until INT_STICKY_1 and INT_STICKY_2 are read to be cleared. */ + 0xFFFFFFFF, 0xFFFFFFFF +}; + +static unsigned int p_tas2557_startup_data[] = { + TAS2557_GPI_PIN_REG, 0x15, /* enable DIN, MCLK, CCI */ + TAS2557_GPIO1_PIN_REG, 0x01, /* enable BCLK */ + TAS2557_GPIO2_PIN_REG, 0x01, /* enable WCLK */ + TAS2557_POWER_CTRL2_REG, 0xA0, /* Class-D, Boost power up */ + TAS2557_POWER_CTRL2_REG, 0xA3, /* Class-D, Boost, IV sense power up */ + TAS2557_POWER_CTRL1_REG, 0xF8, /* PLL, DSP, clock dividers power up */ + TAS2557_UDELAY, 2000, /* delay */ + TAS2557_CLK_ERR_CTRL, 0x2b, /* enable clock error detection */ + 0xFFFFFFFF, 0xFFFFFFFF +}; + +static unsigned int p_tas2557_unmute_data[] = { + TAS2557_MUTE_REG, 0x00, /* unmute */ + TAS2557_SOFT_MUTE_REG, 0x00, /* soft unmute */ + 0xFFFFFFFF, 0xFFFFFFFF +}; + +static unsigned int p_tas2557_shutdown_data[] = { + TAS2557_CLK_ERR_CTRL, 0x00, /* disable clock error detection */ + TAS2557_SOFT_MUTE_REG, 0x01, /* soft mute */ + TAS2557_UDELAY, 10000, /* delay 10ms */ + TAS2557_MUTE_REG, 0x03, /* mute */ + TAS2557_POWER_CTRL1_REG, 0x60, /* DSP power down */ + TAS2557_UDELAY, 2000, /* delay 2ms */ + TAS2557_POWER_CTRL2_REG, 0x00, /* Class-D, Boost power down */ + TAS2557_POWER_CTRL1_REG, 0x00, /* all power down */ + TAS2557_GPIO1_PIN_REG, 0x00, /* disable BCLK */ + TAS2557_GPIO2_PIN_REG, 0x00, /* disable WCLK */ + TAS2557_GPI_PIN_REG, 0x00, /* disable DIN, MCLK, CCI */ + 0xFFFFFFFF, 0xFFFFFFFF +}; + +static int tas2557_dev_load_data(struct tas2557_priv *pTAS2557, + unsigned int *pData) +{ + int ret = 0; + unsigned int n = 0; + unsigned int nRegister; + unsigned int nData; + + do { + nRegister = pData[n * 2]; + nData = pData[n * 2 + 1]; + if (nRegister == TAS2557_UDELAY) + udelay(nData); + else if (nRegister != 0xFFFFFFFF) { + ret = pTAS2557->write(pTAS2557, nRegister, nData); + if (ret < 0) + break; + } + n++; + } while (nRegister != 0xFFFFFFFF); + return ret; +} + +int tas2557_configIRQ(struct tas2557_priv *pTAS2557) +{ + return tas2557_dev_load_data(pTAS2557, p_tas2557_irq_config); +} + +int tas2557_set_bit_rate(struct tas2557_priv *pTAS2557, unsigned int nBitRate) +{ + int ret = 0, n = -1; + + dev_dbg(pTAS2557->dev, "tas2557_set_bit_rate: nBitRate = %d\n", nBitRate); + + switch (nBitRate) { + case 16: + n = 0; + break; + case 20: + n = 1; + break; + case 24: + n = 2; + break; + case 32: + n = 3; + break; + } + + if (n >= 0) + ret = pTAS2557->update_bits(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, 0x18, n<<3); + return ret; +} + +int tas2557_get_bit_rate(struct tas2557_priv *pTAS2557, unsigned char *pBitRate) +{ + int ret = 0; + unsigned int nValue = 0; + unsigned char bitRate; + + ret = pTAS2557->read(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, &nValue); + if (ret >= 0) { + bitRate = (nValue&0x18)>>3; + if (bitRate == 0) + bitRate = 16; + else if (bitRate == 1) + bitRate = 20; + else if (bitRate == 2) + bitRate = 24; + else if (bitRate == 3) + bitRate = 32; + *pBitRate = bitRate; + } + + return ret; +} + +int tas2557_get_DAC_gain(struct tas2557_priv *pTAS2557, unsigned char *pnGain) +{ + int ret = 0; + unsigned int nValue = 0; + + ret = pTAS2557->read(pTAS2557, TAS2557_SPK_CTRL_REG, &nValue); + if (ret >= 0) + *pnGain = ((nValue&TAS2557_DAC_GAIN_MASK)>>TAS2557_DAC_GAIN_SHIFT); + + return ret; +} + +int tas2557_set_DAC_gain(struct tas2557_priv *pTAS2557, unsigned int nGain) +{ + int ret = 0; + + ret = pTAS2557->update_bits(pTAS2557, TAS2557_SPK_CTRL_REG, TAS2557_DAC_GAIN_MASK, + (nGain<mpFirmware->mnConfigurations) { + dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + goto end; + } + + if (!pTAS2557->mbPowerUp) { + dev_err(pTAS2557->dev, "%s, device not powered on\n", __func__); + goto end; + } + + nResult = pTAS2557->bulk_read(pTAS2557, TAS2557_DIE_TEMP_REG, nBuf, 4); + if (nResult >= 0) { + temp = ((int)nBuf[0] << 24) | ((int)nBuf[1] << 16) | ((int)nBuf[2] << 8) | nBuf[3]; + *pTemperature = temp; + } + +end: + + return nResult; +} + +int tas2557_load_platdata(struct tas2557_priv *pTAS2557) +{ + int nResult = 0; + + if (gpio_is_valid(pTAS2557->mnGpioINT)) { + nResult = tas2557_configIRQ(pTAS2557); + if (nResult < 0) + goto end; + } + + nResult = tas2557_set_bit_rate(pTAS2557, pTAS2557->mnI2SBits); + +end: + + return nResult; +} + +int tas2557_load_default(struct tas2557_priv *pTAS2557) +{ + int nResult = 0; + + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_default_data); + if (nResult < 0) + goto end; + + nResult = tas2557_load_platdata(pTAS2557); + if (nResult < 0) + goto end; + + /* enable DOUT tri-state for extra BCLKs */ + nResult = pTAS2557->update_bits(pTAS2557, TAS2557_ASI1_DAC_FORMAT_REG, 0x01, 0x01); +end: + + return nResult; +} + +static void failsafe(struct tas2557_priv *pTAS2557) +{ + dev_err(pTAS2557->dev, "%s\n", __func__); + pTAS2557->mnErrCode |= ERROR_FAILSAFE; + if (hrtimer_active(&pTAS2557->mtimer)) + hrtimer_cancel(&pTAS2557->mtimer); + if(pTAS2557->mnRestart < RESTART_MAX) + { + pTAS2557->mnRestart ++; + msleep(100); + dev_err(pTAS2557->dev, "I2C COMM error, restart SmartAmp.\n"); + schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(100)); + return; + } + pTAS2557->enableIRQ(pTAS2557, false); + tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + pTAS2557->mbPowerUp = false; + pTAS2557->hw_reset(pTAS2557); + pTAS2557->write(pTAS2557, TAS2557_SW_RESET_REG, 0x01); + udelay(1000); + pTAS2557->write(pTAS2557, TAS2557_SPK_CTRL_REG, 0x04); + if (pTAS2557->mpFirmware != NULL) + tas2557_clear_firmware(pTAS2557->mpFirmware); +} + +int tas2557_checkPLL(struct tas2557_priv *pTAS2557) +{ + int nResult = 0; +/* +* TO DO +*/ + + return nResult; +} + +/* +* tas2557_load_coefficient +*/ +static int tas2557_load_coefficient(struct tas2557_priv *pTAS2557, + int nPrevConfig, int nNewConfig, bool bPowerOn) +{ + int nResult = 0; + struct TPLL *pPLL; + struct TProgram *pProgram; + struct TConfiguration *pPrevConfiguration; + struct TConfiguration *pNewConfiguration; + bool bRestorePower = false; + + if (!pTAS2557->mpFirmware->mnConfigurations) { + dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + goto end; + } + + if (nNewConfig >= pTAS2557->mpFirmware->mnConfigurations) { + dev_err(pTAS2557->dev, "%s, invalid configuration New=%d, total=%d\n", + __func__, nNewConfig, pTAS2557->mpFirmware->mnConfigurations); + goto end; + } + + if (nPrevConfig < 0) + pPrevConfiguration = NULL; + else if (nPrevConfig == nNewConfig) { + dev_dbg(pTAS2557->dev, "%s, config [%d] already loaded\n", + __func__, nNewConfig); + goto end; + } else + pPrevConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nPrevConfig]); + + pNewConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nNewConfig]); + pTAS2557->mnCurrentConfiguration = nNewConfig; + if (pPrevConfiguration) { + if (pPrevConfiguration->mnPLL == pNewConfiguration->mnPLL) { + dev_dbg(pTAS2557->dev, "%s, PLL same\n", __func__); + goto prog_coefficient; + } + } + + pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]); + if (bPowerOn) { + dev_dbg(pTAS2557->dev, "%s, power down to load new PLL\n", __func__); + if (hrtimer_active(&pTAS2557->mtimer)) + hrtimer_cancel(&pTAS2557->mtimer); + + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) + pTAS2557->enableIRQ(pTAS2557, false); + + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + if (nResult < 0) + goto end; + bRestorePower = true; + } + + /* load PLL */ + pPLL = &(pTAS2557->mpFirmware->mpPLLs[pNewConfiguration->mnPLL]); + dev_dbg(pTAS2557->dev, "load PLL: %s block for Configuration %s\n", + pPLL->mpName, pNewConfiguration->mpName); + nResult = tas2557_load_block(pTAS2557, &(pPLL->mBlock)); + if (nResult < 0) + goto end; + pTAS2557->mnCurrentSampleRate = pNewConfiguration->mnSamplingRate; + + dev_dbg(pTAS2557->dev, "load configuration %s conefficient pre block\n", + pNewConfiguration->mpName); + nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData), TAS2557_BLOCK_CFG_PRE_DEV_A); + if (nResult < 0) + goto end; + +prog_coefficient: + dev_dbg(pTAS2557->dev, "load new configuration: %s, coeff block data\n", + pNewConfiguration->mpName); + nResult = tas2557_load_data(pTAS2557, &(pNewConfiguration->mData), + TAS2557_BLOCK_CFG_COEFF_DEV_A); + if (nResult < 0) + goto end; + + if (pTAS2557->mpCalFirmware->mnCalibrations) { + nResult = tas2557_set_calibration(pTAS2557, pTAS2557->mnCurrentCalibration); + if (nResult < 0) + goto end; + } + + if (bRestorePower) { + pTAS2557->clearIRQ(pTAS2557); + dev_dbg(pTAS2557->dev, "device powered up, load startup\n"); + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data); + if (nResult < 0) + goto end; + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + nResult = tas2557_checkPLL(pTAS2557); + if (nResult < 0) { + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + pTAS2557->mbPowerUp = false; + goto end; + } + } + dev_dbg(pTAS2557->dev, + "device powered up, load unmute\n"); + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data); + if (nResult < 0) + goto end; + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + pTAS2557->enableIRQ(pTAS2557, true); + if (!hrtimer_active(&pTAS2557->mtimer)) { + pTAS2557->mnDieTvReadCounter = 0; + hrtimer_start(&pTAS2557->mtimer, + ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL); + } + } + } +end: + + pTAS2557->mnNewConfiguration = pTAS2557->mnCurrentConfiguration; + return nResult; +} + +int tas2557_permanent_mute(struct tas2557_priv *pTAS2557, bool bmute) +{ + int nResult = 0; + + nResult = tas2557_enable(pTAS2557, !bmute); + if(nResult) { + dev_dbg(pTAS2557->dev, "set mute = %d faild\n",bmute ); + goto end; + } + + pTAS2557->mbMute = bmute; + + if(bmute) { //make sure codec is permanent mute + p_tas2557_unmute_data[1] = 0x03; + p_tas2557_unmute_data[3] = 0x01; + }else { + p_tas2557_unmute_data[1] = 0x00; + p_tas2557_unmute_data[3] = 0x00; + } + +end: + return nResult; +} +int tas2557_enable(struct tas2557_priv *pTAS2557, bool bEnable) +{ + int nResult = 0; + unsigned int nValue; + const char *pFWName; + struct TProgram *pProgram; + + dev_dbg(pTAS2557->dev, "Enable: %d\n", bEnable); + + if ((pTAS2557->mpFirmware->mnPrograms == 0) + || (pTAS2557->mpFirmware->mnConfigurations == 0)) { + dev_err(pTAS2557->dev, "%s, firmware not loaded, try to load again\n", __func__); + /*Load firmware*/ + if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) { + dev_info(pTAS2557->dev, "PG2.1 Silicon found\n"); + pFWName = TAS2557_AAC_FW_NAME; + } else if (pTAS2557->mnPGID == TAS2557_PG_VERSION_1P0) { + dev_info(pTAS2557->dev, "PG1.0 Silicon found\n"); + pFWName = TAS2557_PG1P0_FW_NAME; + } else { + nResult = -ENOTSUPP; + dev_info(pTAS2557->dev, "unsupport Silicon 0x%x\n", pTAS2557->mnPGID); + goto end; + } + if (pTAS2557->mnSpkType == VENDOR_ID_GOER) + pFWName = TAS2557_GOER_FW_NAME; + else if (pTAS2557->mnSpkType == VENDOR_ID_AAC) + pFWName = TAS2557_AAC_FW_NAME; + else + pFWName = TAS2557_DEFAULT_FW_NAME; + + nResult = request_firmware_nowait(THIS_MODULE, 1, pFWName, + pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready); + if(nResult < 0) + goto end; + dev_err(pTAS2557->dev, "%s, firmware is loaded\n", __func__); + } + + /* check safe guard*/ + nResult = pTAS2557->read(pTAS2557, TAS2557_SAFE_GUARD_REG, &nValue); + if (nResult < 0) + goto end; + if ((nValue&0xff) != TAS2557_SAFE_GUARD_PATTERN) { + dev_err(pTAS2557->dev, "ERROR safe guard failure!\n"); + nResult = -EPIPE; + pTAS2557->mnErrCode = ERROR_SAFE_GUARD; + pTAS2557->mbPowerUp = true; + goto end; + } + + pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]); + if (bEnable) { + if (!pTAS2557->mbPowerUp) { + if (!pTAS2557->mbCalibrationLoaded) { + if (tas2557_set_calibration(pTAS2557, 0xFF) < 0) + dev_err(pTAS2557->dev, "calibration data load fail!\n"); + else + pTAS2557->mbCalibrationLoaded = true; + } + if (pTAS2557->mbLoadConfigurationPrePowerUp) { + dev_dbg(pTAS2557->dev, "load coefficient before power\n"); + pTAS2557->mbLoadConfigurationPrePowerUp = false; + nResult = tas2557_load_coefficient(pTAS2557, + pTAS2557->mnCurrentConfiguration, pTAS2557->mnNewConfiguration, false); + if (nResult < 0) + goto end; + } + + pTAS2557->clearIRQ(pTAS2557); + /* power on device */ + dev_dbg(pTAS2557->dev, "Enable: load startup sequence\n"); + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data); + if (nResult < 0) + goto end; + + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + nResult = tas2557_checkPLL(pTAS2557); + if (nResult < 0) { + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + goto end; + } + } + dev_dbg(pTAS2557->dev, "Enable: load unmute sequence\n"); + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data); + if (nResult < 0) + goto end; + + pTAS2557->mbPowerUp = true; + + nResult = tas2557_get_die_temperature(pTAS2557, &nValue); + if ((nValue == 0x80000000) || (nResult < 0)) { + dev_err(pTAS2557->dev, "%s, thermal sensor is wrong, mute output, mbPower: %d\n", __func__, pTAS2557->mbPowerUp); + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + pTAS2557->mbPowerUp = false; + goto end; + } + + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + /* turn on IRQ */ + pTAS2557->enableIRQ(pTAS2557, true); + if (!hrtimer_active(&pTAS2557->mtimer)) { + pTAS2557->mnDieTvReadCounter = 0; + hrtimer_start(&pTAS2557->mtimer, + ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL); + } + } + pTAS2557->mnRestart = 0; + } + } else { + if (pTAS2557->mbPowerUp) { + if (hrtimer_active(&pTAS2557->mtimer)) + hrtimer_cancel(&pTAS2557->mtimer); + + dev_dbg(pTAS2557->dev, "Enable: load shutdown sequence\n"); + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + /* turn off IRQ */ + pTAS2557->enableIRQ(pTAS2557, false); + } + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + if (nResult < 0) + goto end; + + pTAS2557->mbPowerUp = false; + pTAS2557->mnRestart = 0; + } + } + + nResult = 0; + +end: + if (nResult < 0) { + if (pTAS2557->mnErrCode & (ERROR_DEVA_I2C_COMM | ERROR_PRAM_CRCCHK | ERROR_YRAM_CRCCHK | ERROR_SAFE_GUARD)) + failsafe(pTAS2557); + } + + return nResult; +} + +int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, unsigned int nSamplingRate) +{ + int nResult = 0; + struct TConfiguration *pConfiguration; + unsigned int nConfiguration; + + dev_dbg(pTAS2557->dev, "tas2557_setup_clocks: nSamplingRate = %d [Hz]\n", + nSamplingRate); + + if ((!pTAS2557->mpFirmware->mpPrograms) || + (!pTAS2557->mpFirmware->mpConfigurations)) { + dev_err(pTAS2557->dev, "Firmware not loaded\n"); + nResult = -EINVAL; + goto end; + } + + pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]); + if (pConfiguration->mnSamplingRate == nSamplingRate) { + dev_info(pTAS2557->dev, "Sampling rate for current configuration matches: %d\n", + nSamplingRate); + nResult = 0; + goto end; + } + + for (nConfiguration = 0; + nConfiguration < pTAS2557->mpFirmware->mnConfigurations; + nConfiguration++) { + pConfiguration = + &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]); + if ((pConfiguration->mnSamplingRate == nSamplingRate) + && (pConfiguration->mnProgram == pTAS2557->mnCurrentProgram)) { + dev_info(pTAS2557->dev, + "Found configuration: %s, with compatible sampling rate %d\n", + pConfiguration->mpName, nSamplingRate); + nResult = tas2557_load_configuration(pTAS2557, nConfiguration, false); + goto end; + } + } + + dev_err(pTAS2557->dev, "Cannot find a configuration that supports sampling rate: %d\n", + nSamplingRate); + +end: + + return nResult; +} + +static void fw_print_header(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware) +{ + dev_info(pTAS2557->dev, "FW Size = %d", pFirmware->mnFWSize); + dev_info(pTAS2557->dev, "Checksum = 0x%04X", pFirmware->mnChecksum); + dev_info(pTAS2557->dev, "PPC Version = 0x%04X", pFirmware->mnPPCVersion); + dev_info(pTAS2557->dev, "FW Version = 0x%04X", pFirmware->mnFWVersion); + dev_info(pTAS2557->dev, "Driver Version= 0x%04X", pFirmware->mnDriverVersion); + dev_info(pTAS2557->dev, "Timestamp = %d", pFirmware->mnTimeStamp); + dev_info(pTAS2557->dev, "DDC Name = %s", pFirmware->mpDDCName); + dev_info(pTAS2557->dev, "Description = %s", pFirmware->mpDescription); +} + +inline unsigned int fw_convert_number(unsigned char *pData) +{ + return pData[3] + (pData[2] << 8) + (pData[1] << 16) + (pData[0] << 24); +} + +static int fw_parse_header(struct tas2557_priv *pTAS2557, + struct TFirmware *pFirmware, unsigned char *pData, unsigned int nSize) +{ + unsigned char *pDataStart = pData; + unsigned int n; + unsigned char pMagicNumber[] = { 0x35, 0x35, 0x35, 0x32 }; + + if (nSize < 104) { + dev_err(pTAS2557->dev, "Firmware: Header too short"); + return -EINVAL; + } + + if (memcmp(pData, pMagicNumber, 4)) { + dev_err(pTAS2557->dev, "Firmware: Magic number doesn't match"); + return -EINVAL; + } + pData += 4; + + pFirmware->mnFWSize = fw_convert_number(pData); + pData += 4; + + pFirmware->mnChecksum = fw_convert_number(pData); + pData += 4; + + pFirmware->mnPPCVersion = fw_convert_number(pData); + pData += 4; + + pFirmware->mnFWVersion = fw_convert_number(pData); + pData += 4; + + pFirmware->mnDriverVersion = fw_convert_number(pData); + pData += 4; + + pFirmware->mnTimeStamp = fw_convert_number(pData); + pData += 4; + + memcpy(pFirmware->mpDDCName, pData, 64); + pData += 64; + + n = strlen(pData); + pFirmware->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL); + pData += n + 1; + if ((pData - pDataStart) >= nSize) { + dev_err(pTAS2557->dev, "Firmware: Header too short after DDC description"); + return -EINVAL; + } + + pFirmware->mnDeviceFamily = fw_convert_number(pData); + pData += 4; + if (pFirmware->mnDeviceFamily != 0) { + dev_err(pTAS2557->dev, + "deviceFamily %d, not TAS device", pFirmware->mnDeviceFamily); + return -EINVAL; + } + + pFirmware->mnDevice = fw_convert_number(pData); + pData += 4; + + if (pFirmware->mnDevice != 2) { + dev_err(pTAS2557->dev, + "device %d, not TAS2557 Dual Mono", pFirmware->mnDevice); + return -EINVAL; + } + + fw_print_header(pTAS2557, pFirmware); + return pData - pDataStart; +} + +static int fw_parse_block_data(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware, + struct TBlock *pBlock, unsigned char *pData) +{ + unsigned char *pDataStart = pData; + unsigned int n; + + pBlock->mnType = fw_convert_number(pData); + pData += 4; + + if (pFirmware->mnDriverVersion >= PPC_DRIVER_CRCCHK) { + pBlock->mbPChkSumPresent = pData[0]; + pData++; + + pBlock->mnPChkSum = pData[0]; + pData++; + + pBlock->mbYChkSumPresent = pData[0]; + pData++; + + pBlock->mnYChkSum = pData[0]; + pData++; + } else { + pBlock->mbPChkSumPresent = 0; + pBlock->mbYChkSumPresent = 0; + } + + pBlock->mnCommands = fw_convert_number(pData); + pData += 4; + + n = pBlock->mnCommands * 4; + pBlock->mpData = kmemdup(pData, n, GFP_KERNEL); + pData += n; + return pData - pDataStart; +} + +static int fw_parse_data(struct tas2557_priv *pTAS2557, struct TFirmware *pFirmware, + struct TData *pImageData, unsigned char *pData) +{ + unsigned char *pDataStart = pData; + unsigned int nBlock; + unsigned int n; + + memcpy(pImageData->mpName, pData, 64); + pData += 64; + + n = strlen(pData); + pImageData->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL); + pData += n + 1; + + pImageData->mnBlocks = (pData[0] << 8) + pData[1]; + pData += 2; + + pImageData->mpBlocks = + kmalloc(sizeof(struct TBlock) * pImageData->mnBlocks, GFP_KERNEL); + + for (nBlock = 0; nBlock < pImageData->mnBlocks; nBlock++) { + n = fw_parse_block_data(pTAS2557, pFirmware, + &(pImageData->mpBlocks[nBlock]), pData); + pData += n; + } + return pData - pDataStart; +} + +static int fw_parse_pll_data(struct tas2557_priv *pTAS2557, + struct TFirmware *pFirmware, unsigned char *pData) +{ + unsigned char *pDataStart = pData; + unsigned int n; + unsigned int nPLL; + struct TPLL *pPLL; + + pFirmware->mnPLLs = (pData[0] << 8) + pData[1]; + pData += 2; + + if (pFirmware->mnPLLs == 0) + goto end; + + pFirmware->mpPLLs = kmalloc_array(pFirmware->mnPLLs, sizeof(struct TPLL), GFP_KERNEL); + for (nPLL = 0; nPLL < pFirmware->mnPLLs; nPLL++) { + pPLL = &(pFirmware->mpPLLs[nPLL]); + + memcpy(pPLL->mpName, pData, 64); + pData += 64; + + n = strlen(pData); + pPLL->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL); + pData += n + 1; + + n = fw_parse_block_data(pTAS2557, pFirmware, &(pPLL->mBlock), pData); + pData += n; + } + +end: + return pData - pDataStart; +} + +static int fw_parse_program_data(struct tas2557_priv *pTAS2557, + struct TFirmware *pFirmware, unsigned char *pData) +{ + unsigned char *pDataStart = pData; + unsigned int n; + unsigned int nProgram; + struct TProgram *pProgram; + + pFirmware->mnPrograms = (pData[0] << 8) + pData[1]; + pData += 2; + + if (pFirmware->mnPrograms == 0) + goto end; + + pFirmware->mpPrograms = + kmalloc(sizeof(struct TProgram) * pFirmware->mnPrograms, GFP_KERNEL); + for (nProgram = 0; nProgram < pFirmware->mnPrograms; nProgram++) { + pProgram = &(pFirmware->mpPrograms[nProgram]); + memcpy(pProgram->mpName, pData, 64); + pData += 64; + + n = strlen(pData); + pProgram->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL); + pData += n + 1; + + pProgram->mnAppMode = pData[0]; + pData++; + + pProgram->mnBoost = (pData[0] << 8) + pData[1]; + pData += 2; + + n = fw_parse_data(pTAS2557, pFirmware, &(pProgram->mData), pData); + pData += n; + } + +end: + + return pData - pDataStart; +} + +static int fw_parse_configuration_data(struct tas2557_priv *pTAS2557, + struct TFirmware *pFirmware, unsigned char *pData) +{ + unsigned char *pDataStart = pData; + unsigned int n; + unsigned int nConfiguration; + struct TConfiguration *pConfiguration; + + pFirmware->mnConfigurations = (pData[0] << 8) + pData[1]; + pData += 2; + + if (pFirmware->mnConfigurations == 0) + goto end; + + pFirmware->mpConfigurations = + kmalloc(sizeof(struct TConfiguration) * pFirmware->mnConfigurations, + GFP_KERNEL); + for (nConfiguration = 0; nConfiguration < pFirmware->mnConfigurations; + nConfiguration++) { + pConfiguration = &(pFirmware->mpConfigurations[nConfiguration]); + memcpy(pConfiguration->mpName, pData, 64); + pData += 64; + + n = strlen(pData); + pConfiguration->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL); + pData += n + 1; + + if ((pFirmware->mnDriverVersion >= PPC_DRIVER_CONFDEV) + || ((pFirmware->mnDriverVersion >= PPC_DRIVER_CFGDEV_NONCRC) + && (pFirmware->mnDriverVersion < PPC_DRIVER_CRCCHK))) { + pConfiguration->mnDevices = (pData[0] << 8) + pData[1]; + pData += 2; + } else + pConfiguration->mnDevices = 1; + + pConfiguration->mnProgram = pData[0]; + pData++; + + pConfiguration->mnPLL = pData[0]; + pData++; + + pConfiguration->mnSamplingRate = fw_convert_number(pData); + pData += 4; + + if (pFirmware->mnDriverVersion >= PPC_DRIVER_MTPLLSRC) { + pConfiguration->mnPLLSrc = pData[0]; + pData++; + + pConfiguration->mnPLLSrcRate = fw_convert_number(pData); + pData += 4; + } + + n = fw_parse_data(pTAS2557, pFirmware, &(pConfiguration->mData), pData); + pData += n; + } + +end: + + return pData - pDataStart; +} + +int fw_parse_calibration_data(struct tas2557_priv *pTAS2557, + struct TFirmware *pFirmware, unsigned char *pData) +{ + unsigned char *pDataStart = pData; + unsigned int n; + unsigned int nCalibration; + struct TCalibration *pCalibration; + + pFirmware->mnCalibrations = (pData[0] << 8) + pData[1]; + pData += 2; + + if (pFirmware->mnCalibrations == 0) + goto end; + + pFirmware->mpCalibrations = + kmalloc(sizeof(struct TCalibration) * pFirmware->mnCalibrations, GFP_KERNEL); + for (nCalibration = 0; + nCalibration < pFirmware->mnCalibrations; + nCalibration++) { + pCalibration = &(pFirmware->mpCalibrations[nCalibration]); + memcpy(pCalibration->mpName, pData, 64); + pData += 64; + + n = strlen(pData); + pCalibration->mpDescription = kmemdup(pData, n + 1, GFP_KERNEL); + pData += n + 1; + + pCalibration->mnProgram = pData[0]; + pData++; + + pCalibration->mnConfiguration = pData[0]; + pData++; + + n = fw_parse_data(pTAS2557, pFirmware, &(pCalibration->mData), pData); + pData += n; + } + +end: + + return pData - pDataStart; +} + +static int fw_parse(struct tas2557_priv *pTAS2557, + struct TFirmware *pFirmware, unsigned char *pData, unsigned int nSize) +{ + int nPosition = 0; + + nPosition = fw_parse_header(pTAS2557, pFirmware, pData, nSize); + if (nPosition < 0) { + dev_err(pTAS2557->dev, "Firmware: Wrong Header"); + return -EINVAL; + } + + if (nPosition >= nSize) { + dev_err(pTAS2557->dev, "Firmware: Too short"); + return -EINVAL; + } + + pData += nPosition; + nSize -= nPosition; + nPosition = 0; + + nPosition = fw_parse_pll_data(pTAS2557, pFirmware, pData); + + pData += nPosition; + nSize -= nPosition; + nPosition = 0; + + nPosition = fw_parse_program_data(pTAS2557, pFirmware, pData); + + pData += nPosition; + nSize -= nPosition; + nPosition = 0; + + nPosition = fw_parse_configuration_data(pTAS2557, pFirmware, pData); + + pData += nPosition; + nSize -= nPosition; + nPosition = 0; + + if (nSize > 64) + nPosition = fw_parse_calibration_data(pTAS2557, pFirmware, pData); + return 0; +} + + +static const unsigned char crc8_lookup_table[CRC8_TABLE_SIZE] = { +0x00, 0x4D, 0x9A, 0xD7, 0x79, 0x34, 0xE3, 0xAE, 0xF2, 0xBF, 0x68, 0x25, 0x8B, 0xC6, 0x11, 0x5C, +0xA9, 0xE4, 0x33, 0x7E, 0xD0, 0x9D, 0x4A, 0x07, 0x5B, 0x16, 0xC1, 0x8C, 0x22, 0x6F, 0xB8, 0xF5, +0x1F, 0x52, 0x85, 0xC8, 0x66, 0x2B, 0xFC, 0xB1, 0xED, 0xA0, 0x77, 0x3A, 0x94, 0xD9, 0x0E, 0x43, +0xB6, 0xFB, 0x2C, 0x61, 0xCF, 0x82, 0x55, 0x18, 0x44, 0x09, 0xDE, 0x93, 0x3D, 0x70, 0xA7, 0xEA, +0x3E, 0x73, 0xA4, 0xE9, 0x47, 0x0A, 0xDD, 0x90, 0xCC, 0x81, 0x56, 0x1B, 0xB5, 0xF8, 0x2F, 0x62, +0x97, 0xDA, 0x0D, 0x40, 0xEE, 0xA3, 0x74, 0x39, 0x65, 0x28, 0xFF, 0xB2, 0x1C, 0x51, 0x86, 0xCB, +0x21, 0x6C, 0xBB, 0xF6, 0x58, 0x15, 0xC2, 0x8F, 0xD3, 0x9E, 0x49, 0x04, 0xAA, 0xE7, 0x30, 0x7D, +0x88, 0xC5, 0x12, 0x5F, 0xF1, 0xBC, 0x6B, 0x26, 0x7A, 0x37, 0xE0, 0xAD, 0x03, 0x4E, 0x99, 0xD4, +0x7C, 0x31, 0xE6, 0xAB, 0x05, 0x48, 0x9F, 0xD2, 0x8E, 0xC3, 0x14, 0x59, 0xF7, 0xBA, 0x6D, 0x20, +0xD5, 0x98, 0x4F, 0x02, 0xAC, 0xE1, 0x36, 0x7B, 0x27, 0x6A, 0xBD, 0xF0, 0x5E, 0x13, 0xC4, 0x89, +0x63, 0x2E, 0xF9, 0xB4, 0x1A, 0x57, 0x80, 0xCD, 0x91, 0xDC, 0x0B, 0x46, 0xE8, 0xA5, 0x72, 0x3F, +0xCA, 0x87, 0x50, 0x1D, 0xB3, 0xFE, 0x29, 0x64, 0x38, 0x75, 0xA2, 0xEF, 0x41, 0x0C, 0xDB, 0x96, +0x42, 0x0F, 0xD8, 0x95, 0x3B, 0x76, 0xA1, 0xEC, 0xB0, 0xFD, 0x2A, 0x67, 0xC9, 0x84, 0x53, 0x1E, +0xEB, 0xA6, 0x71, 0x3C, 0x92, 0xDF, 0x08, 0x45, 0x19, 0x54, 0x83, 0xCE, 0x60, 0x2D, 0xFA, 0xB7, +0x5D, 0x10, 0xC7, 0x8A, 0x24, 0x69, 0xBE, 0xF3, 0xAF, 0xE2, 0x35, 0x78, 0xD6, 0x9B, 0x4C, 0x01, +0xF4, 0xB9, 0x6E, 0x23, 0x8D, 0xC0, 0x17, 0x5A, 0x06, 0x4B, 0x9C, 0xD1, 0x7F, 0x32, 0xE5, 0xA8 +}; + +static int isInPageYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData, + unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len) +{ + int nResult = 0; + + if (nBook == TAS2557_YRAM_BOOK1) { + if (nPage == TAS2557_YRAM1_PAGE) { + if (nReg >= TAS2557_YRAM1_START_REG) { + pCRCData->mnOffset = nReg; + pCRCData->mnLen = len; + nResult = 1; + } else if ((nReg + len) > TAS2557_YRAM1_START_REG) { + pCRCData->mnOffset = TAS2557_YRAM1_START_REG; + pCRCData->mnLen = len - (TAS2557_YRAM1_START_REG - nReg); + nResult = 1; + } else + nResult = 0; + } else if (nPage == TAS2557_YRAM3_PAGE) { + if (nReg > TAS2557_YRAM3_END_REG) { + nResult = 0; + } else if (nReg >= TAS2557_YRAM3_START_REG) { + if ((nReg + len) > TAS2557_YRAM3_END_REG) { + pCRCData->mnOffset = nReg; + pCRCData->mnLen = TAS2557_YRAM3_END_REG - nReg + 1; + nResult = 1; + } else { + pCRCData->mnOffset = nReg; + pCRCData->mnLen = len; + nResult = 1; + } + } else { + if ((nReg + (len - 1)) < TAS2557_YRAM3_START_REG) + nResult = 0; + else { + pCRCData->mnOffset = TAS2557_YRAM3_START_REG; + pCRCData->mnLen = len - (TAS2557_YRAM3_START_REG - nReg); + nResult = 1; + } + } + } + } else if (nBook == TAS2557_YRAM_BOOK2) { + if (nPage == TAS2557_YRAM5_PAGE) { + if (nReg > TAS2557_YRAM5_END_REG) { + nResult = 0; + } else if (nReg >= TAS2557_YRAM5_START_REG) { + if ((nReg + len) > TAS2557_YRAM5_END_REG) { + pCRCData->mnOffset = nReg; + pCRCData->mnLen = TAS2557_YRAM5_END_REG - nReg + 1; + nResult = 1; + } else { + pCRCData->mnOffset = nReg; + pCRCData->mnLen = len; + nResult = 1; + } + } else { + if ((nReg + (len - 1)) < TAS2557_YRAM5_START_REG) + nResult = 0; + else { + pCRCData->mnOffset = TAS2557_YRAM5_START_REG; + pCRCData->mnLen = len - (TAS2557_YRAM5_START_REG - nReg); + nResult = 1; + } + } + } + } else + nResult = 0; + + return nResult; +} + +static int isInBlockYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData, + unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len) +{ + int nResult; + + if (nBook == TAS2557_YRAM_BOOK1) { + if (nPage < TAS2557_YRAM2_START_PAGE) + nResult = 0; + else if (nPage <= TAS2557_YRAM2_END_PAGE) { + if (nReg > TAS2557_YRAM2_END_REG) + nResult = 0; + else if (nReg >= TAS2557_YRAM2_START_REG) { + pCRCData->mnOffset = nReg; + pCRCData->mnLen = len; + nResult = 1; + } else { + if ((nReg + (len - 1)) < TAS2557_YRAM2_START_REG) + nResult = 0; + else { + pCRCData->mnOffset = TAS2557_YRAM2_START_REG; + pCRCData->mnLen = nReg + len - TAS2557_YRAM2_START_REG; + nResult = 1; + } + } + } else + nResult = 0; + } else if (nBook == TAS2557_YRAM_BOOK2) { + if (nPage < TAS2557_YRAM4_START_PAGE) + nResult = 0; + else if (nPage <= TAS2557_YRAM4_END_PAGE) { + if (nReg > TAS2557_YRAM2_END_REG) + nResult = 0; + else if (nReg >= TAS2557_YRAM2_START_REG) { + pCRCData->mnOffset = nReg; + pCRCData->mnLen = len; + nResult = 1; + } else { + if ((nReg + (len - 1)) < TAS2557_YRAM2_START_REG) + nResult = 0; + else { + pCRCData->mnOffset = TAS2557_YRAM2_START_REG; + pCRCData->mnLen = nReg + len - TAS2557_YRAM2_START_REG; + nResult = 1; + } + } + } else + nResult = 0; + } else + nResult = 0; + + return nResult; +} + + +static int isYRAM(struct tas2557_priv *pTAS2557, struct TYCRC *pCRCData, + unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char len) +{ + int nResult; + + nResult = isInPageYRAM(pTAS2557, pCRCData, nBook, nPage, nReg, len); + + if (nResult == 0) + nResult = isInBlockYRAM(pTAS2557, pCRCData, nBook, nPage, nReg, len); + + return nResult; +} + +/* + * crc8 - calculate a crc8 over the given input data. + * + * table: crc table used for calculation. + * pdata: pointer to data buffer. + * nbytes: number of bytes in data buffer. + * crc: previous returned crc8 value. + */ +static u8 ti_crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc) +{ + /* loop over the buffer data */ + while (nbytes-- > 0) + crc = table[(crc ^ *pdata++) & 0xff]; + + return crc; +} + +static int doSingleRegCheckSum(struct tas2557_priv *pTAS2557, + unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned char nValue) +{ + int nResult = 0; + struct TYCRC sCRCData; + unsigned int nData1 = 0; + + if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG)) + && (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG)) + && (nReg >= TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG)) + && (nReg <= (TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG) + 4))) { + /* DSP swap command, pass */ + nResult = 0; + goto end; + } + + nResult = isYRAM(pTAS2557, &sCRCData, nBook, nPage, nReg, 1); + if (nResult == 1) { + nResult = pTAS2557->read(pTAS2557, TAS2557_REG(nBook, nPage, nReg), &nData1); + if (nResult < 0) + goto end; + + if (nData1 != nValue) { + dev_err(pTAS2557->dev, "error2 (line %d),B[0x%x]P[0x%x]R[0x%x] W[0x%x], R[0x%x]\n", + __LINE__, nBook, nPage, nReg, nValue, nData1); + nResult = -EAGAIN; + goto end; + } + + nResult = ti_crc8(crc8_lookup_table, &nValue, 1, 0); + } + +end: + + return nResult; +} + +static int doMultiRegCheckSum(struct tas2557_priv *pTAS2557, + unsigned char nBook, unsigned char nPage, unsigned char nReg, unsigned int len) +{ + int nResult = 0, i; + unsigned char nCRCChkSum = 0; + unsigned char nBuf1[128]; + struct TYCRC TCRCData; + + if ((nReg + len-1) > 127) { + nResult = -EINVAL; + dev_err(pTAS2557->dev, "firmware error\n"); + goto end; + } + + if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG)) + && (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG)) + && (nReg == TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG)) + && (len == 4)) { + /* DSP swap command, pass */ + nResult = 0; + goto end; + } + + nResult = isYRAM(pTAS2557, &TCRCData, nBook, nPage, nReg, len); + if (nResult == 1) { + if (len == 1) { + dev_err(pTAS2557->dev, "firmware error\n"); + nResult = -EINVAL; + goto end; + } else { + nResult = pTAS2557->bulk_read(pTAS2557, TAS2557_REG(nBook, nPage, TCRCData.mnOffset), nBuf1, TCRCData.mnLen); + if (nResult < 0) + goto end; + + for (i = 0; i < TCRCData.mnLen; i++) { + if ((nBook == TAS2557_BOOK_ID(TAS2557_SA_COEFF_SWAP_REG)) + && (nPage == TAS2557_PAGE_ID(TAS2557_SA_COEFF_SWAP_REG)) + && ((i + TCRCData.mnOffset) + >= TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG)) + && ((i + TCRCData.mnOffset) + <= (TAS2557_PAGE_REG(TAS2557_SA_COEFF_SWAP_REG) + 4))) { + /* DSP swap command, bypass */ + continue; + } else + nCRCChkSum += ti_crc8(crc8_lookup_table, &nBuf1[i], 1, 0); + } + + nResult = nCRCChkSum; + } + } + +end: + + return nResult; +} + +static int tas2557_load_block(struct tas2557_priv *pTAS2557, struct TBlock *pBlock) +{ + int nResult = 0; + unsigned int nCommand = 0; + unsigned char nBook; + unsigned char nPage; + unsigned char nOffset; + unsigned char nData; + unsigned int nLength; + unsigned int nSleep; + unsigned char nCRCChkSum = 0; + unsigned int nValue1; + int nRetry = 6; + unsigned char *pData = pBlock->mpData; + + dev_dbg(pTAS2557->dev, "TAS2557 load block: Type = %d, commands = %d\n", + pBlock->mnType, pBlock->mnCommands); +start: + if (pBlock->mbPChkSumPresent) { + nResult = pTAS2557->write(pTAS2557, TAS2557_CRC_RESET_REG, 1); + if (nResult < 0) + goto end; + } + + if (pBlock->mbYChkSumPresent) + nCRCChkSum = 0; + + nCommand = 0; + + while (nCommand < pBlock->mnCommands) { + pData = pBlock->mpData + nCommand * 4; + + nBook = pData[0]; + nPage = pData[1]; + nOffset = pData[2]; + nData = pData[3]; + + nCommand++; + + if (nOffset <= 0x7F) { + nResult = pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), nData); + if (nResult < 0) + goto end; + if (pBlock->mbYChkSumPresent) { + nResult = doSingleRegCheckSum(pTAS2557, nBook, nPage, nOffset, nData); + if (nResult < 0) + goto check; + nCRCChkSum += (unsigned char)nResult; + } + } else if (nOffset == 0x81) { + nSleep = (nBook << 8) + nPage; + msleep(nSleep); + } else if (nOffset == 0x85) { + pData += 4; + nLength = (nBook << 8) + nPage; + nBook = pData[0]; + nPage = pData[1]; + nOffset = pData[2]; + if (nLength > 1) { + nResult = pTAS2557->bulk_write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), pData + 3, nLength); + if (nResult < 0) + goto end; + if (pBlock->mbYChkSumPresent) { + nResult = doMultiRegCheckSum(pTAS2557, nBook, nPage, nOffset, nLength); + if (nResult < 0) + goto check; + nCRCChkSum += (unsigned char)nResult; + } + } else { + nResult = pTAS2557->write(pTAS2557, TAS2557_REG(nBook, nPage, nOffset), pData[3]); + if (nResult < 0) + goto end; + if (pBlock->mbYChkSumPresent) { + nResult = doSingleRegCheckSum(pTAS2557, nBook, nPage, nOffset, pData[3]); + if (nResult < 0) + goto check; + nCRCChkSum += (unsigned char)nResult; + } + } + + nCommand++; + + if (nLength >= 2) + nCommand += ((nLength - 2) / 4) + 1; + } + } + if (pBlock->mbPChkSumPresent) { + nResult = pTAS2557->read(pTAS2557, TAS2557_CRC_CHECKSUM_REG, &nValue1); + if (nResult < 0) + goto end; + if ((nValue1&0xff) != pBlock->mnPChkSum) { + dev_err(pTAS2557->dev, "Block PChkSum Error: FW = 0x%x, Reg = 0x%x\n", + pBlock->mnPChkSum, (nValue1&0xff)); + nResult = -EAGAIN; + pTAS2557->mnErrCode |= ERROR_PRAM_CRCCHK; + goto check; + } + + nResult = 0; + pTAS2557->mnErrCode &= ~ERROR_PRAM_CRCCHK; + dev_dbg(pTAS2557->dev, "Block[0x%x] PChkSum match\n", pBlock->mnType); + } + + if (pBlock->mbYChkSumPresent) { + if (nCRCChkSum != pBlock->mnYChkSum) { + dev_err(pTAS2557->dev, "Block YChkSum Error: FW = 0x%x, YCRC = 0x%x\n", + pBlock->mnYChkSum, nCRCChkSum); + nResult = -EAGAIN; + pTAS2557->mnErrCode |= ERROR_YRAM_CRCCHK; + goto check; + } + pTAS2557->mnErrCode &= ~ERROR_YRAM_CRCCHK; + nResult = 0; + dev_dbg(pTAS2557->dev, "Block[0x%x] YChkSum match\n", pBlock->mnType); + } + +check: + if (nResult == -EAGAIN) { + nRetry--; + if (nRetry > 0) + goto start; + } + +end: + if (nResult < 0) { + dev_err(pTAS2557->dev, "Block (%d) load error\n", + pBlock->mnType); + } + return nResult; +} + +static int tas2557_load_data(struct tas2557_priv *pTAS2557, struct TData *pData, unsigned int nType) +{ + int nResult = 0; + unsigned int nBlock; + struct TBlock *pBlock; + + dev_dbg(pTAS2557->dev, + "TAS2557 load data: %s, Blocks = %d, Block Type = %d\n", pData->mpName, pData->mnBlocks, nType); + + for (nBlock = 0; nBlock < pData->mnBlocks; nBlock++) { + pBlock = &(pData->mpBlocks[nBlock]); + if (pBlock->mnType == nType) { + nResult = tas2557_load_block(pTAS2557, pBlock); + if (nResult < 0) + break; + } + } + + return nResult; +} + +static int tas2557_load_configuration(struct tas2557_priv *pTAS2557, + unsigned int nConfiguration, bool bLoadSame) +{ + int nResult = 0; + struct TConfiguration *pCurrentConfiguration = NULL; + struct TConfiguration *pNewConfiguration = NULL; + + dev_dbg(pTAS2557->dev, "%s: %d\n", __func__, nConfiguration); + + if ((!pTAS2557->mpFirmware->mpPrograms) || + (!pTAS2557->mpFirmware->mpConfigurations)) { + dev_err(pTAS2557->dev, "Firmware not loaded\n"); + nResult = 0; + goto end; + } + + if (nConfiguration >= pTAS2557->mpFirmware->mnConfigurations) { + dev_err(pTAS2557->dev, "Configuration %d doesn't exist\n", + nConfiguration); + nResult = 0; + goto end; + } + + if ((!pTAS2557->mbLoadConfigurationPrePowerUp) + && (nConfiguration == pTAS2557->mnCurrentConfiguration) + && (!bLoadSame)) { + dev_info(pTAS2557->dev, "Configuration %d is already loaded\n", + nConfiguration); + nResult = 0; + goto end; + } + + pCurrentConfiguration = + &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]); + pNewConfiguration = + &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]); + if (pNewConfiguration->mnProgram != pCurrentConfiguration->mnProgram) { + dev_err(pTAS2557->dev, "Configuration %d, %s doesn't share the same program as current %d\n", + nConfiguration, pNewConfiguration->mpName, pCurrentConfiguration->mnProgram); + nResult = 0; + goto end; + } + + if (pNewConfiguration->mnPLL >= pTAS2557->mpFirmware->mnPLLs) { + dev_err(pTAS2557->dev, "Configuration %d, %s doesn't have a valid PLL index %d\n", + nConfiguration, pNewConfiguration->mpName, pNewConfiguration->mnPLL); + nResult = 0; + goto end; + } + + if (pTAS2557->mbPowerUp) { + pTAS2557->mbLoadConfigurationPrePowerUp = false; + nResult = tas2557_load_coefficient(pTAS2557, pTAS2557->mnCurrentConfiguration, nConfiguration, true); + } else { + dev_dbg(pTAS2557->dev, + "TAS2557 was powered down, will load coefficient when power up\n"); + pTAS2557->mbLoadConfigurationPrePowerUp = true; + pTAS2557->mnNewConfiguration = nConfiguration; + } + +end: + + if (nResult < 0) { + if (pTAS2557->mnErrCode & (ERROR_DEVA_I2C_COMM | ERROR_PRAM_CRCCHK | ERROR_YRAM_CRCCHK)) + failsafe(pTAS2557); + } + + return nResult; +} + +int tas2557_set_config(struct tas2557_priv *pTAS2557, int config) +{ + struct TConfiguration *pConfiguration; + struct TProgram *pProgram; + unsigned int nProgram = pTAS2557->mnCurrentProgram; + unsigned int nConfiguration = config; + int nResult = 0; + + if ((!pTAS2557->mpFirmware->mpPrograms) || + (!pTAS2557->mpFirmware->mpConfigurations)) { + dev_err(pTAS2557->dev, "Firmware not loaded\n"); + nResult = -EINVAL; + goto end; + } + + if (nConfiguration >= pTAS2557->mpFirmware->mnConfigurations) { + dev_err(pTAS2557->dev, "Configuration %d doesn't exist\n", + nConfiguration); + nResult = -EINVAL; + goto end; + } + + pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[nConfiguration]); + pProgram = &(pTAS2557->mpFirmware->mpPrograms[nProgram]); + + if (nProgram != pConfiguration->mnProgram) { + dev_err(pTAS2557->dev, + "Configuration %d, %s with Program %d isn't compatible with existing Program %d, %s\n", + nConfiguration, pConfiguration->mpName, pConfiguration->mnProgram, + nProgram, pProgram->mpName); + nResult = -EINVAL; + goto end; + } + + nResult = tas2557_load_configuration(pTAS2557, nConfiguration, false); + +end: + + return nResult; +} + +void tas2557_clear_firmware(struct TFirmware *pFirmware) +{ + unsigned int n, nn; + + if (!pFirmware) + return; + + kfree(pFirmware->mpDescription); + + if (pFirmware->mpPLLs != NULL) { + for (n = 0; n < pFirmware->mnPLLs; n++) { + kfree(pFirmware->mpPLLs[n].mpDescription); + kfree(pFirmware->mpPLLs[n].mBlock.mpData); + } + kfree(pFirmware->mpPLLs); + } + + if (pFirmware->mpPrograms != NULL) { + for (n = 0; n < pFirmware->mnPrograms; n++) { + kfree(pFirmware->mpPrograms[n].mpDescription); + kfree(pFirmware->mpPrograms[n].mData.mpDescription); + for (nn = 0; nn < pFirmware->mpPrograms[n].mData.mnBlocks; nn++) + kfree(pFirmware->mpPrograms[n].mData.mpBlocks[nn].mpData); + kfree(pFirmware->mpPrograms[n].mData.mpBlocks); + } + kfree(pFirmware->mpPrograms); + } + + if (pFirmware->mpConfigurations != NULL) { + for (n = 0; n < pFirmware->mnConfigurations; n++) { + kfree(pFirmware->mpConfigurations[n].mpDescription); + kfree(pFirmware->mpConfigurations[n].mData.mpDescription); + for (nn = 0; nn < pFirmware->mpConfigurations[n].mData.mnBlocks; nn++) + kfree(pFirmware->mpConfigurations[n].mData.mpBlocks[nn].mpData); + kfree(pFirmware->mpConfigurations[n].mData.mpBlocks); + } + kfree(pFirmware->mpConfigurations); + } + + if (pFirmware->mpCalibrations != NULL) { + for (n = 0; n < pFirmware->mnCalibrations; n++) { + kfree(pFirmware->mpCalibrations[n].mpDescription); + kfree(pFirmware->mpCalibrations[n].mData.mpDescription); + for (nn = 0; nn < pFirmware->mpCalibrations[n].mData.mnBlocks; nn++) + kfree(pFirmware->mpCalibrations[n].mData.mpBlocks[nn].mpData); + kfree(pFirmware->mpCalibrations[n].mData.mpBlocks); + } + kfree(pFirmware->mpCalibrations); + } + + memset(pFirmware, 0x00, sizeof(struct TFirmware)); +} + +static int tas2557_load_calibration(struct tas2557_priv *pTAS2557, char *pFileName) +{ + int nResult = 0; + struct file *nFile=NULL; + mm_segment_t fs; + unsigned char pBuffer[1000]; + int nSize = 0; + loff_t pos = 0; + + dev_dbg(pTAS2557->dev, "%s:\n", __func__); + fs = get_fs(); + set_fs(KERNEL_DS); + nFile = filp_open(pFileName, O_RDONLY, 0); + + dev_info(pTAS2557->dev, "TAS2557 calibration file = %s\n", pFileName); + if (IS_ERR(nFile)) { + if (PTR_ERR(nFile) == -ENOENT) + dev_err(pTAS2557->dev, "TAS2557 calibration file %s is not exit\n", pFileName); + else + dev_err(pTAS2557->dev, "TAS2557 cannot open calibration file: %s errno:%d\n", pFileName, (int)PTR_ERR(nFile)); + } else { + pos = nFile->f_pos; + nSize = vfs_read(nFile, pBuffer, 1000, &pos); + filp_close(nFile,NULL); + } + + set_fs(fs); + if (!nSize) + goto end; + + tas2557_clear_firmware(pTAS2557->mpCalFirmware); + dev_info(pTAS2557->dev, "TAS2557 calibration file size = %d\n", nSize); + nResult = fw_parse(pTAS2557, pTAS2557->mpCalFirmware, pBuffer, nSize); + + if (nResult) + dev_err(pTAS2557->dev, "TAS2557 calibration file is corrupt\n"); + else + dev_info(pTAS2557->dev, "TAS2557 calibration: %d calibrations\n", pTAS2557->mpCalFirmware->mnCalibrations); + +end: + return nResult; +} + +static bool tas2557_get_coefficient_in_block(struct tas2557_priv *pTAS2557, + struct TBlock *pBlock, int nReg, int *pnValue) +{ + int nCoefficient = 0; + bool bFound = false; + unsigned char *pCommands; + int nBook, nPage, nOffset, len; + int i, n; + + pCommands = pBlock->mpData; + for (i = 0 ; i < pBlock->mnCommands;) { + nBook = pCommands[4 * i + 0]; + nPage = pCommands[4 * i + 1]; + nOffset = pCommands[4 * i + 2]; + if ((nOffset < 0x7f) || (nOffset == 0x81)) + i++; + else if (nOffset == 0x85) { + len = ((int)nBook << 8) | nPage; + nBook = pCommands[4 * i + 4]; + nPage = pCommands[4 * i + 5]; + nOffset = pCommands[4 * i + 6]; + n = 4 * i + 7; + i += 2; + i += ((len - 1) / 4); + if ((len - 1) % 4) + i++; + if ((nBook != TAS2557_BOOK_ID(nReg)) + || (nPage != TAS2557_PAGE_ID(nReg))) + continue; + if (nOffset > TAS2557_PAGE_REG(nReg)) + continue; + if ((len + nOffset) >= (TAS2557_PAGE_REG(nReg) + 4)) { + n += (TAS2557_PAGE_REG(nReg) - nOffset); + nCoefficient = ((int)pCommands[n] << 24) + | ((int)pCommands[n + 1] << 16) + | ((int)pCommands[n + 2] << 8) + | (int)pCommands[n + 3]; + bFound = true; + break; + } + } else { + dev_err(pTAS2557->dev, "%s, format error %d\n", __func__, nOffset); + break; + } + } + + if (bFound) { + *pnValue = nCoefficient; + dev_dbg(pTAS2557->dev, "%s, B[0x%x]P[0x%x]R[0x%x]=0x%x\n", __func__, + TAS2557_BOOK_ID(nReg), TAS2557_PAGE_ID(nReg), TAS2557_PAGE_REG(nReg), + nCoefficient); + } + + return bFound; +} + +static bool tas2557_get_coefficient_in_data(struct tas2557_priv *pTAS2557, + struct TData *pData, int blockType, int nReg, int *pnValue) +{ + bool bFound = false; + struct TBlock *pBlock; + int i; + + for (i = 0; i < pData->mnBlocks; i++) { + pBlock = &(pData->mpBlocks[i]); + if (pBlock->mnType == blockType) { + bFound = tas2557_get_coefficient_in_block(pTAS2557, + pBlock, nReg, pnValue); + if (bFound) + break; + } + } + + return bFound; +} + +static bool tas2557_find_Tmax_in_configuration(struct tas2557_priv *pTAS2557, + struct TConfiguration *pConfiguration, int *pnTMax) +{ + struct TData *pData; + bool bFound = false; + int nBlockType, nReg, nCoefficient; + + if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) + nReg = TAS2557_PG2P1_CALI_T_REG; + else + nReg = TAS2557_PG1P0_CALI_T_REG; + + nBlockType = TAS2557_BLOCK_CFG_COEFF_DEV_A; + + pData = &(pConfiguration->mData); + bFound = tas2557_get_coefficient_in_data(pTAS2557, pData, nBlockType, nReg, &nCoefficient); + if (bFound) + *pnTMax = nCoefficient; + + return bFound; +} + +void tas2557_fw_ready(const struct firmware *pFW, void *pContext) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *) pContext; + int nResult; + unsigned int nProgram = 0; + unsigned int nSampleRate = 0; + +#ifdef CONFIG_TAS2557_CODEC + mutex_lock(&pTAS2557->codec_lock); +#endif + +#ifdef CONFIG_TAS2557_MISC + mutex_lock(&pTAS2557->file_lock); +#endif + + dev_info(pTAS2557->dev, "%s:\n", __func__); + + if (unlikely(!pFW) || unlikely(!pFW->data)) { + dev_err(pTAS2557->dev, "firmware is not loaded.\n"); + goto end; + } + + if (pTAS2557->mpFirmware->mpConfigurations) { + nProgram = pTAS2557->mnCurrentProgram; + nSampleRate = pTAS2557->mnCurrentSampleRate; + dev_dbg(pTAS2557->dev, "clear current firmware\n"); + tas2557_clear_firmware(pTAS2557->mpFirmware); + } + + nResult = fw_parse(pTAS2557, pTAS2557->mpFirmware, (unsigned char *)(pFW->data), pFW->size); + release_firmware(pFW); + if (nResult < 0) { + dev_err(pTAS2557->dev, "firmware is corrupt\n"); + goto end; + } + + if (!pTAS2557->mpFirmware->mnPrograms) { + dev_err(pTAS2557->dev, "firmware contains no programs\n"); + nResult = -EINVAL; + goto end; + } + + if (!pTAS2557->mpFirmware->mnConfigurations) { + dev_err(pTAS2557->dev, "firmware contains no configurations\n"); + nResult = -EINVAL; + goto end; + } + + if (nProgram >= pTAS2557->mpFirmware->mnPrograms) { + dev_info(pTAS2557->dev, + "no previous program, set to default\n"); + nProgram = 0; + } + + pTAS2557->mnCurrentSampleRate = nSampleRate; + nResult = tas2557_set_program(pTAS2557, nProgram, -1); + +end: + +#ifdef CONFIG_TAS2557_CODEC + mutex_unlock(&pTAS2557->codec_lock); +#endif + +#ifdef CONFIG_TAS2557_MISC + mutex_unlock(&pTAS2557->file_lock); +#endif +} + +int tas2557_set_program(struct tas2557_priv *pTAS2557, + unsigned int nProgram, int nConfig) +{ + struct TProgram *pProgram; + unsigned int nConfiguration = 0; + unsigned int nSampleRate = 0; + unsigned char nGain; + bool bFound = false; + int nResult = 0; + + if ((!pTAS2557->mpFirmware->mpPrograms) || + (!pTAS2557->mpFirmware->mpConfigurations)) { + dev_err(pTAS2557->dev, "Firmware not loaded\n"); + nResult = 0; + goto end; + } + + if (nProgram >= pTAS2557->mpFirmware->mnPrograms) { + dev_err(pTAS2557->dev, "TAS2557: Program %d doesn't exist\n", + nProgram); + nResult = 0; + goto end; + } + + if (nConfig < 0) { + nConfiguration = 0; + nSampleRate = pTAS2557->mnCurrentSampleRate; + while (!bFound && (nConfiguration < pTAS2557->mpFirmware->mnConfigurations)) { + if (pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnProgram == nProgram) { + if (nSampleRate == 0) { + bFound = true; + dev_info(pTAS2557->dev, "find default configuration %d\n", nConfiguration); + } else if (nSampleRate == pTAS2557->mpFirmware->mpConfigurations[nConfiguration].mnSamplingRate) { + bFound = true; + dev_info(pTAS2557->dev, "find matching configuration %d\n", nConfiguration); + } else { + nConfiguration++; + } + } else { + nConfiguration++; + } + } + if (!bFound) { + dev_err(pTAS2557->dev, + "Program %d, no valid configuration found for sample rate %d, ignore\n", + nProgram, nSampleRate); + nResult = 0; + goto end; + } + } else { + if (pTAS2557->mpFirmware->mpConfigurations[nConfig].mnProgram != nProgram) { + dev_err(pTAS2557->dev, "%s, configuration program doesn't match\n", __func__); + nResult = 0; + goto end; + } + nConfiguration = nConfig; + } + + pProgram = &(pTAS2557->mpFirmware->mpPrograms[nProgram]); + if (pTAS2557->mbPowerUp) { + dev_info(pTAS2557->dev, + "device powered up, power down to load program %d (%s)\n", + nProgram, pProgram->mpName); + if (hrtimer_active(&pTAS2557->mtimer)) + hrtimer_cancel(&pTAS2557->mtimer); + + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) + pTAS2557->enableIRQ(pTAS2557, false); + + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + if (nResult < 0) + goto end; + } + + pTAS2557->hw_reset(pTAS2557); + nResult = pTAS2557->write(pTAS2557, TAS2557_SW_RESET_REG, 0x01); + if (nResult < 0) + goto end; + msleep(1); + nResult = tas2557_load_default(pTAS2557); + if (nResult < 0) + goto end; + + dev_info(pTAS2557->dev, "load program %d (%s)\n", nProgram, pProgram->mpName); + nResult = tas2557_load_data(pTAS2557, &(pProgram->mData), TAS2557_BLOCK_PGM_DEV_A); + if (nResult < 0) + goto end; + pTAS2557->mnCurrentProgram = nProgram; + + nResult = tas2557_get_DAC_gain(pTAS2557, &nGain); + if (nResult < 0) + goto end; + pTAS2557->mnDevGain = nGain; + pTAS2557->mnDevCurrentGain = nGain; + + nResult = tas2557_load_coefficient(pTAS2557, -1, nConfiguration, false); + if (nResult < 0) + goto end; + + if (pTAS2557->mbPowerUp) { + pTAS2557->clearIRQ(pTAS2557); + dev_dbg(pTAS2557->dev, "device powered up, load startup\n"); + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_startup_data); + if (nResult < 0) + goto end; + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + nResult = tas2557_checkPLL(pTAS2557); + if (nResult < 0) { + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_shutdown_data); + pTAS2557->mbPowerUp = false; + goto end; + } + } + dev_dbg(pTAS2557->dev, "device powered up, load unmute\n"); + nResult = tas2557_dev_load_data(pTAS2557, p_tas2557_unmute_data); + if (nResult < 0) + goto end; + + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + pTAS2557->enableIRQ(pTAS2557, true); + if (!hrtimer_active(&pTAS2557->mtimer)) { + pTAS2557->mnDieTvReadCounter = 0; + hrtimer_start(&pTAS2557->mtimer, + ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL); + } + } + } + +end: + + if (nResult < 0) { + if (pTAS2557->mnErrCode & (ERROR_DEVA_I2C_COMM | ERROR_PRAM_CRCCHK | ERROR_YRAM_CRCCHK)) + failsafe(pTAS2557); + } + return nResult; +} + +int tas2557_set_calibration(struct tas2557_priv *pTAS2557, int nCalibration) +{ + struct TCalibration *pCalibration = NULL; + struct TConfiguration *pConfiguration; + struct TProgram *pProgram; + int nTmax = 0; + bool bFound = false; + int nResult = 0; + + if ((!pTAS2557->mpFirmware->mpPrograms) + || (!pTAS2557->mpFirmware->mpConfigurations)) { + dev_err(pTAS2557->dev, "Firmware not loaded\n\r"); + nResult = 0; + goto end; + } + + if (nCalibration == 0x00FF) { + nResult = tas2557_load_calibration(pTAS2557, TAS2557_CAL_NAME); + if (nResult < 0) { + dev_info(pTAS2557->dev, "load new calibration file %s fail %d\n", + TAS2557_CAL_NAME, nResult); + goto end; + } + nCalibration = 0; + } + + if (nCalibration >= pTAS2557->mpCalFirmware->mnCalibrations) { + dev_err(pTAS2557->dev, + "Calibration %d doesn't exist\n", nCalibration); + nResult = 0; + goto end; + } + + pTAS2557->mnCurrentCalibration = nCalibration; + if (pTAS2557->mbLoadConfigurationPrePowerUp) + goto end; + + pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[nCalibration]); + pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]); + pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]); + if (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE) { + if (pTAS2557->mbBypassTMax) { + bFound = tas2557_find_Tmax_in_configuration(pTAS2557, pConfiguration, &nTmax); + if (bFound && (nTmax == TAS2557_COEFFICIENT_TMAX)) { + dev_dbg(pTAS2557->dev, "%s, config[%s] bypass load calibration\n", + __func__, pConfiguration->mpName); + goto end; + } + } + + dev_dbg(pTAS2557->dev, "%s, load calibration\n", __func__); + nResult = tas2557_load_data(pTAS2557, &(pCalibration->mData), TAS2557_BLOCK_CFG_COEFF_DEV_A); + if (nResult < 0) + goto end; + } + +end: + if (nResult < 0) { + tas2557_clear_firmware(pTAS2557->mpCalFirmware); + nResult = tas2557_set_program(pTAS2557, pTAS2557->mnCurrentProgram, pTAS2557->mnCurrentConfiguration); + } + + return nResult; +} + +bool tas2557_get_Cali_prm_r0(struct tas2557_priv *pTAS2557, int *prm_r0) +{ + struct TCalibration *pCalibration; + struct TData *pData; + int nReg; + int nCali_Re; + bool bFound = false; + int nBlockType; + + if (!pTAS2557->mpCalFirmware->mnCalibrations) { + dev_err(pTAS2557->dev, "%s, no calibration data\n", __func__); + goto end; + } + + if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) + nReg = TAS2557_PG2P1_CALI_R0_REG; + else + nReg = TAS2557_PG1P0_CALI_R0_REG; + + nBlockType = TAS2557_BLOCK_CFG_COEFF_DEV_A; + + pCalibration = &(pTAS2557->mpCalFirmware->mpCalibrations[pTAS2557->mnCurrentCalibration]); + pData = &(pCalibration->mData); + + bFound = tas2557_get_coefficient_in_data(pTAS2557, pData, nBlockType, nReg, &nCali_Re); + +end: + + if (bFound) + *prm_r0 = nCali_Re; + + return bFound; +} + +int spk_id_get(struct device_node *np) +{ + int id; + int state; + + state = spk_id_get_pin_3state(np); + if (state < 0) { + pr_err("%s: Can not get id pin state, %d\n", __func__, state); + return VENDOR_ID_NONE; + } + + switch (state) { + case PIN_PULL_DOWN: + id = VENDOR_ID_AAC; + break; + case PIN_PULL_UP: + id = VENDOR_ID_UNKNOWN; + break; + case PIN_FLOAT: + id = VENDOR_ID_GOER; + break; + default: + id = VENDOR_ID_UNKNOWN; + break; + } + return id; +} + +int tas2557_parse_dt(struct device *dev, struct tas2557_priv *pTAS2557) +{ + struct device_node *np = dev->of_node; + int rc = 0, ret = 0; + unsigned int value; + + pTAS2557->spk_id_gpio_p = of_parse_phandle(np, + "ti,spk-id-pin", 0); + if (!pTAS2557->spk_id_gpio_p) { + dev_dbg(pTAS2557->dev, "property %s not detected in node %s", + "ti,spk-id-pin", np->full_name); + pTAS2557->mnSpkType = VENDOR_ID_NONE; + } else { + pTAS2557->mnSpkType = spk_id_get(pTAS2557->spk_id_gpio_p); + } + dev_dbg(pTAS2557->dev, "spk is is %d", pTAS2557->mnSpkType); + + pTAS2557->mnResetGPIO = of_get_named_gpio(np, "ti,cdc-reset-gpio", 0); + if (!gpio_is_valid(pTAS2557->mnResetGPIO)) { + dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n", + "ti,cdc-reset-gpio", np->full_name, + pTAS2557->mnResetGPIO); + ret = -EINVAL; + goto end; + } else + dev_dbg(pTAS2557->dev, "ti,cdc-reset-gpio=%d\n", pTAS2557->mnResetGPIO); + + pTAS2557->mnGpioINT = of_get_named_gpio(np, "ti,irq-gpio", 0); + if (!gpio_is_valid(pTAS2557->mnGpioINT)) + dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n", + "ti,irq-gpio", np->full_name, + pTAS2557->mnGpioINT); + + + rc = of_property_read_u32(np, "ti,i2s-bits", &value); + if (rc) + dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n", + "ti,i2s-bits", np->full_name, rc); + else + pTAS2557->mnI2SBits = value; + + rc = of_property_read_u32(np, "ti,bypass-tmax", &value); + if (rc) + dev_err(pTAS2557->dev, "Looking up %s property in node %s failed %d\n", + "ti,bypass-tmax", np->full_name, rc); + else + pTAS2557->mbBypassTMax = (value > 0); + +end: + + return ret; +} + +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("TAS2557 common functions for Android Linux"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557-core.h b/techpack/audio/asoc/codecs/tas2557/tas2557-core.h new file mode 100755 index 000000000000..5081d5bb4364 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557-core.h @@ -0,0 +1,81 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557-core.h +** +** Description: +** header file for tas2557-core.c +** +** ============================================================================= +*/ + +#ifndef _TAS2557_CORE_H +#define _TAS2557_CORE_H + +#include "tas2557.h" + +#define TAS2557_YRAM_BOOK1 140 + +#define TAS2557_YRAM1_PAGE 42 +#define TAS2557_YRAM1_START_REG 88 +#define TAS2557_YRAM1_END_REG 127 + +#define TAS2557_YRAM2_START_PAGE 43 +#define TAS2557_YRAM2_END_PAGE 49 +#define TAS2557_YRAM2_START_REG 8 +#define TAS2557_YRAM2_END_REG 127 + +#define TAS2557_YRAM3_PAGE 50 +#define TAS2557_YRAM3_START_REG 8 +#define TAS2557_YRAM3_END_REG 27 + +/* should not include B0_P53_R44-R47 */ +#define TAS2557_YRAM_BOOK2 0 +#define TAS2557_YRAM4_START_PAGE 50 +#define TAS2557_YRAM4_END_PAGE 60 +#define TAS2557_YRAM4_START_REG 8 +#define TAS2557_YRAM4_END_REG 127 + +#define TAS2557_YRAM5_PAGE 61 +#define TAS2557_YRAM5_START_REG 8 +#define TAS2557_YRAM5_END_REG 27 + +#define TAS2557_COEFFICIENT_TMAX 0x7fffffff +#define TAS2557_SAFE_GUARD_PATTERN 0x5a +#define LOW_TEMPERATURE_CHECK_PERIOD 5000 /* 5 second */ + +struct TYCRC { + unsigned char mnOffset; + unsigned char mnLen; +}; + +int tas2557_enable(struct tas2557_priv *pTAS2557, bool bEnable); +int tas2557_permanent_mute(struct tas2557_priv *pTAS2557, bool bmute); +int tas2557_SA_DevChnSetup(struct tas2557_priv *pTAS2557, unsigned int mode); +int tas2557_get_die_temperature(struct tas2557_priv *pTAS2557, int *pTemperature); +int tas2557_set_sampling_rate(struct tas2557_priv *pTAS2557, unsigned int nSamplingRate); +int tas2557_set_bit_rate(struct tas2557_priv *pTAS2557, unsigned int nBitRate); +int tas2557_get_bit_rate(struct tas2557_priv *pTAS2557, unsigned char *pBitRate); +int tas2557_set_config(struct tas2557_priv *pTAS2557, int config); +void tas2557_fw_ready(const struct firmware *pFW, void *pContext); +bool tas2557_get_Cali_prm_r0(struct tas2557_priv *pTAS2557, int *prm_r0); +int tas2557_set_program(struct tas2557_priv *pTAS2557, unsigned int nProgram, int nConfig); +int tas2557_set_calibration(struct tas2557_priv *pTAS2557, int nCalibration); +int tas2557_load_default(struct tas2557_priv *pTAS2557); +int tas2557_parse_dt(struct device *dev, struct tas2557_priv *pTAS2557); +int tas2557_get_DAC_gain(struct tas2557_priv *pTAS2557, unsigned char *pnGain); +int tas2557_set_DAC_gain(struct tas2557_priv *pTAS2557, unsigned int nGain); +int tas2557_configIRQ(struct tas2557_priv *pTAS2557); +int spk_id_get(struct device_node *np); + +#endif /* _TAS2557_CORE_H */ diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557-misc.c b/techpack/audio/asoc/codecs/tas2557/tas2557-misc.c new file mode 100644 index 000000000000..5f342e60e33a --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557-misc.c @@ -0,0 +1,603 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557-misc.c +** +** Description: +** misc driver for Texas Instruments TAS2557 High Performance 4W Smart Amplifier +** +** ============================================================================= +*/ + +#ifdef CONFIG_TAS2557_MISC + +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas2557.h" +#include "tas2557-core.h" +#include "tas2557-misc.h" + +static int g_logEnable = 1; +static struct tas2557_priv *g_tas2557; + +static int tas2557_file_open(struct inode *inode, struct file *file) +{ + struct tas2557_priv *pTAS2557 = g_tas2557; + + if (!try_module_get(THIS_MODULE)) + return -ENODEV; + + file->private_data = (void *)pTAS2557; + if (g_logEnable) + dev_info(pTAS2557->dev, "%s\n", __func__); + return 0; +} + +static int tas2557_file_release(struct inode *inode, struct file *file) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)file->private_data; + + if (g_logEnable) + dev_info(pTAS2557->dev, "%s\n", __func__); + file->private_data = (void *)NULL; + module_put(THIS_MODULE); + + return 0; +} + +static ssize_t tas2557_file_read(struct file *file, char *buf, size_t count, loff_t *ppos) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)file->private_data; + int ret = 0; + unsigned int nValue = 0; + unsigned char value = 0; + unsigned char *p_kBuf = NULL; + + mutex_lock(&pTAS2557->file_lock); + + switch (pTAS2557->mnDBGCmd) { + case TIAUDIO_CMD_REG_READ: { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_READ: current_reg = 0x%x, count=%d\n", + pTAS2557->mnCurrentReg, (int)count); + if (count == 1) { + ret = pTAS2557->read(pTAS2557, pTAS2557->mnCurrentReg, &nValue); + if (ret < 0) + break; + + value = (u8)nValue; + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_READ: nValue=0x%x, value=0x%x\n", nValue, value); + ret = copy_to_user(buf, &value, 1); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + } else if (count > 1) { + p_kBuf = kzalloc(count, GFP_KERNEL); + if (p_kBuf != NULL) { + ret = pTAS2557->bulk_read(pTAS2557, pTAS2557->mnCurrentReg, p_kBuf, count); + if (ret < 0) + break; + ret = copy_to_user(buf, p_kBuf, count); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + kfree(p_kBuf); + } else + dev_err(pTAS2557->dev, "read no mem\n"); + } + } + break; + + case TIAUDIO_CMD_PROGRAM: { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_PROGRAM: count = %d\n", (int)count); + + if (count == PROGRAM_BUF_SIZE) { + p_kBuf = kzalloc(count, GFP_KERNEL); + if (p_kBuf != NULL) { + struct TProgram *pProgram = + &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]); + p_kBuf[0] = pTAS2557->mpFirmware->mnPrograms; + p_kBuf[1] = pTAS2557->mnCurrentProgram; + p_kBuf[2] = pProgram->mnAppMode; + p_kBuf[3] = (pProgram->mnBoost&0xff00)>>8; + p_kBuf[4] = (pProgram->mnBoost&0x00ff); + memcpy(&p_kBuf[5], pProgram->mpName, FW_NAME_SIZE); + strlcpy(&p_kBuf[5+FW_NAME_SIZE], pProgram->mpDescription, strlen(pProgram->mpDescription) + 1); + ret = copy_to_user(buf, p_kBuf, count); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + kfree(p_kBuf); + } else + dev_err(pTAS2557->dev, "read no mem\n"); + } else + dev_err(pTAS2557->dev, "read buffer not sufficient\n"); + } else + dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + } + break; + + case TIAUDIO_CMD_CONFIGURATION: { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_CONFIGURATION: count = %d\n", (int)count); + if (count == CONFIGURATION_BUF_SIZE) { + p_kBuf = kzalloc(count, GFP_KERNEL); + if (p_kBuf != NULL) { + struct TConfiguration *pConfiguration = &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]); + + p_kBuf[0] = pTAS2557->mpFirmware->mnConfigurations; + p_kBuf[1] = pTAS2557->mnCurrentConfiguration; + memcpy(&p_kBuf[2], pConfiguration->mpName, FW_NAME_SIZE); + p_kBuf[2+FW_NAME_SIZE] = pConfiguration->mnProgram; + p_kBuf[3+FW_NAME_SIZE] = pConfiguration->mnPLL; + p_kBuf[4+FW_NAME_SIZE] = (pConfiguration->mnSamplingRate&0x000000ff); + p_kBuf[5+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8); + p_kBuf[6+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16); + p_kBuf[7+FW_NAME_SIZE] = ((pConfiguration->mnSamplingRate&0xff000000)>>24); + strlcpy(&p_kBuf[8+FW_NAME_SIZE], pConfiguration->mpDescription, strlen(pConfiguration->mpDescription)+1); + ret = copy_to_user(buf, p_kBuf, count); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + kfree(p_kBuf); + } else + dev_err(pTAS2557->dev, "read no mem\n"); + } else + dev_err(pTAS2557->dev, "read buffer not sufficient\n"); + } else + dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + } + break; + + case TIAUDIO_CMD_FW_TIMESTAMP: { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_FW_TIMESTAMP: count = %d\n", (int)count); + + if (count == 4) { + p_kBuf = kzalloc(count, GFP_KERNEL); + if (p_kBuf != NULL) { + p_kBuf[0] = (pTAS2557->mpFirmware->mnTimeStamp&0x000000ff); + p_kBuf[1] = ((pTAS2557->mpFirmware->mnTimeStamp&0x0000ff00)>>8); + p_kBuf[2] = ((pTAS2557->mpFirmware->mnTimeStamp&0x00ff0000)>>16); + p_kBuf[3] = ((pTAS2557->mpFirmware->mnTimeStamp&0xff000000)>>24); + ret = copy_to_user(buf, p_kBuf, count); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + kfree(p_kBuf); + } else + dev_err(pTAS2557->dev, "read no mem\n"); + } + } + break; + + case TIAUDIO_CMD_CALIBRATION: { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_CALIBRATION: count = %d\n", (int)count); + + if (count == 1) { + unsigned char curCal = pTAS2557->mnCurrentCalibration; + + ret = copy_to_user(buf, &curCal, 1); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + } + } + break; + + case TIAUDIO_CMD_SAMPLERATE: { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_SAMPLERATE: count = %d\n", (int)count); + if (count == 4) { + p_kBuf = kzalloc(count, GFP_KERNEL); + if (p_kBuf != NULL) { + struct TConfiguration *pConfiguration = + &(pTAS2557->mpFirmware->mpConfigurations[pTAS2557->mnCurrentConfiguration]); + + p_kBuf[0] = (pConfiguration->mnSamplingRate&0x000000ff); + p_kBuf[1] = ((pConfiguration->mnSamplingRate&0x0000ff00)>>8); + p_kBuf[2] = ((pConfiguration->mnSamplingRate&0x00ff0000)>>16); + p_kBuf[3] = ((pConfiguration->mnSamplingRate&0xff000000)>>24); + + ret = copy_to_user(buf, p_kBuf, count); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + + kfree(p_kBuf); + } else + dev_err(pTAS2557->dev, "read no mem\n"); + } + } + break; + + case TIAUDIO_CMD_BITRATE: { + if (g_logEnable) + dev_info(pTAS2557->dev, + "TIAUDIO_CMD_BITRATE: count = %d\n", (int)count); + + if (count == 1) { + unsigned char bitRate = 0; + ret = tas2557_get_bit_rate(pTAS2557, &bitRate); + if (ret >= 0) { + ret = copy_to_user(buf, &bitRate, 1); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + } + } + } + break; + + case TIAUDIO_CMD_DACVOLUME: { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_DACVOLUME: count = %d\n", (int)count); + + if (count == 1) { + unsigned char volume = 0; + + ret = tas2557_get_DAC_gain(pTAS2557, &volume); + if (ret >= 0) { + ret = copy_to_user(buf, &volume, 1); + if (ret != 0) { + /* Failed to copy all the data, exit */ + dev_err(pTAS2557->dev, "copy to user fail %d\n", ret); + } + } + } + } + break; + } + pTAS2557->mnDBGCmd = 0; + + mutex_unlock(&pTAS2557->file_lock); + return count; +} + +static ssize_t tas2557_file_write(struct file *file, const char *buf, size_t count, loff_t *ppos) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)file->private_data; + int ret = 0; + unsigned char *p_kBuf = NULL; + unsigned int reg = 0; + unsigned int len = 0; + + mutex_lock(&pTAS2557->file_lock); + + p_kBuf = kzalloc(count, GFP_KERNEL); + if (p_kBuf == NULL) { + dev_err(pTAS2557->dev, "write no mem\n"); + goto err; + } + + ret = copy_from_user(p_kBuf, buf, count); + if (ret != 0) { + dev_err(pTAS2557->dev, "copy_from_user failed.\n"); + goto err; + } + + pTAS2557->mnDBGCmd = p_kBuf[0]; + switch (pTAS2557->mnDBGCmd) { + case TIAUDIO_CMD_REG_WITE: + if (count > 5) { + reg = ((unsigned int)p_kBuf[1] << 24) + + ((unsigned int)p_kBuf[2] << 16) + + ((unsigned int)p_kBuf[3] << 8) + + (unsigned int)p_kBuf[4]; + len = count - 5; + if (len == 1) { + ret = pTAS2557->write(pTAS2557, reg, p_kBuf[5]); + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_WITE, Reg=0x%x, Val=0x%x\n", reg, p_kBuf[5]); + } else + ret = pTAS2557->bulk_write(pTAS2557, reg, &p_kBuf[5], len); + } else + dev_err(pTAS2557->dev, "%s, write len fail, count=%d.\n", __func__, (int)count); + pTAS2557->mnDBGCmd = 0; + break; + + case TIAUDIO_CMD_REG_READ: + if (count == 5) { + pTAS2557->mnCurrentReg = ((unsigned int)p_kBuf[1] << 24) + + ((unsigned int)p_kBuf[2] << 16) + + ((unsigned int)p_kBuf[3] << 8) + + (unsigned int)p_kBuf[4]; + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_REG_READ whole=0x%x\n", pTAS2557->mnCurrentReg); + } else + dev_err(pTAS2557->dev, "read len fail.\n"); + break; + + case TIAUDIO_CMD_DEBUG_ON: + if (count == 2) + g_logEnable = p_kBuf[1]; + + pTAS2557->mnDBGCmd = 0; + break; + + case TIAUDIO_CMD_PROGRAM: + { + if (count == 2) { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) { + int config = -1; + + if (p_kBuf[1] == pTAS2557->mnCurrentProgram) + config = pTAS2557->mnCurrentConfiguration; + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_PROGRAM, set to %d, cfg=%d\n", p_kBuf[1], config); + tas2557_set_program(pTAS2557, p_kBuf[1], config); + pTAS2557->mnDBGCmd = 0; + } else + dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + } + } + break; + + case TIAUDIO_CMD_CONFIGURATION: + { + if (count == 2) { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_CONFIGURATION, set to %d\n", p_kBuf[1]); + tas2557_set_config(pTAS2557, p_kBuf[1]); + pTAS2557->mnDBGCmd = 0; + } else + dev_err(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + } + } + break; + + case TIAUDIO_CMD_FW_TIMESTAMP: + /*let go*/ + break; + + case TIAUDIO_CMD_CALIBRATION: + { + if (count == 2) { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_CALIBRATION, set to %d\n", p_kBuf[1]); + tas2557_set_calibration(pTAS2557, p_kBuf[1]); + pTAS2557->mnDBGCmd = 0; + } + } + } + break; + + case TIAUDIO_CMD_SAMPLERATE: + if (count == 5) { + unsigned int nSampleRate = ((unsigned int)p_kBuf[1] << 24) + + ((unsigned int)p_kBuf[2] << 16) + + ((unsigned int)p_kBuf[3] << 8) + + (unsigned int)p_kBuf[4]; + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_SAMPLERATE, set to %d\n", nSampleRate); + + tas2557_set_sampling_rate(pTAS2557, nSampleRate); + } + break; + + case TIAUDIO_CMD_BITRATE: + if (count == 2) { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_BITRATE, set to %d\n", p_kBuf[1]); + + tas2557_set_bit_rate(pTAS2557, p_kBuf[1]); + } + break; + + case TIAUDIO_CMD_DACVOLUME: + if (count == 2) { + unsigned char volume; + + volume = (p_kBuf[1] & 0x0f); + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_DACVOLUME, set to %d\n", volume); + + tas2557_set_DAC_gain(pTAS2557, volume); + } + break; + + case TIAUDIO_CMD_SPEAKER: + if (count == 2) { + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_SPEAKER, set to %d\n", p_kBuf[1]); + tas2557_enable(pTAS2557, (p_kBuf[1] > 0)); + } + break; + + case TIAUDIO_CMD_FW_RELOAD: + if (count == 1) { + const char *pFWName; + if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) + pFWName = TAS2557_AAC_FW_NAME; + else if (pTAS2557->mnPGID == TAS2557_PG_VERSION_1P0) + pFWName = TAS2557_PG1P0_FW_NAME; + else + break; + + if (pTAS2557->mnSpkType == VENDOR_ID_GOER) + pFWName = TAS2557_GOER_FW_NAME; + else if (pTAS2557->mnSpkType == VENDOR_ID_AAC) + pFWName = TAS2557_AAC_FW_NAME; + else if (pTAS2557->mnSpkType == VENDOR_ID_SSI) + pFWName = TAS2557_SSI_FW_NAME; + else + pFWName = TAS2557_DEFAULT_FW_NAME; + + ret = request_firmware_nowait(THIS_MODULE, 1, pFWName, + pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready); + + if (g_logEnable) + dev_info(pTAS2557->dev, "TIAUDIO_CMD_FW_RELOAD: ret = %d\n", ret); + } + break; + + default: + pTAS2557->mnDBGCmd = 0; + break; + } + +err: + if (p_kBuf != NULL) + kfree(p_kBuf); + + mutex_unlock(&pTAS2557->file_lock); + + return count; +} + +static long tas2557_file_unlocked_ioctl(struct file *file, unsigned int cmd, unsigned long arg) +{ + struct tas2557_priv *pTAS2557 = file->private_data; + int ret = 0; + + mutex_lock(&pTAS2557->file_lock); + + switch (cmd) { + case SMARTPA_SPK_DAC_VOLUME: + { + } + break; + + case SMARTPA_SPK_POWER_ON: + { + tas2557_enable(pTAS2557, true); + } + break; + + case SMARTPA_SPK_POWER_OFF: + { + tas2557_enable(pTAS2557, false); + } + break; + + case SMARTPA_SPK_SWITCH_PROGRAM: + { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) + tas2557_set_program(pTAS2557, arg, -1); + } + break; + + case SMARTPA_SPK_SWITCH_CONFIGURATION: + { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) + tas2557_set_config(pTAS2557, arg); + } + break; + + case SMARTPA_SPK_SWITCH_CALIBRATION: + { + if ((pTAS2557->mpFirmware->mnConfigurations > 0) + && (pTAS2557->mpFirmware->mnPrograms > 0)) + tas2557_set_calibration(pTAS2557, arg); + } + break; + + case SMARTPA_SPK_SET_SAMPLERATE: + { + tas2557_set_sampling_rate(pTAS2557, arg); + } + break; + + case SMARTPA_SPK_SET_BITRATE: + { + tas2557_set_bit_rate(pTAS2557, arg); + } + break; + } + + mutex_unlock(&pTAS2557->file_lock); + return ret; +} + +static const struct file_operations fops = { + .owner = THIS_MODULE, + .read = tas2557_file_read, + .write = tas2557_file_write, + .unlocked_ioctl = tas2557_file_unlocked_ioctl, + .open = tas2557_file_open, + .release = tas2557_file_release, +}; + +#define MODULE_NAME "tas2557" +static struct miscdevice tas2557_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = MODULE_NAME, + .fops = &fops, +}; + +int tas2557_register_misc(struct tas2557_priv *pTAS2557) +{ + int ret = 0; + + g_tas2557 = pTAS2557; + + ret = misc_register(&tas2557_misc); + if (ret) + dev_err(pTAS2557->dev, "TAS2557 misc fail: %d\n", ret); + + dev_info(pTAS2557->dev, "%s, leave\n", __func__); + + return ret; +} + +int tas2557_deregister_misc(struct tas2557_priv *pTAS2557) +{ + misc_deregister(&tas2557_misc); + return 0; +} + +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("TAS2557 Misc Smart Amplifier driver"); +MODULE_LICENSE("GPL v2"); +#endif diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557-misc.h b/techpack/audio/asoc/codecs/tas2557/tas2557-misc.h new file mode 100644 index 000000000000..a82f1d74b3c4 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557-misc.h @@ -0,0 +1,57 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557-misc.h +** +** Description: +** header file for tas2557-misc.c +** +** ============================================================================= +*/ + +#ifndef _TAS2557_MISC_H +#define _TAS2557_MISC_H + +#define FW_NAME_SIZE 64 +#define FW_DESCRIPTION_SIZE 256 +#define PROGRAM_BUF_SIZE (5 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE) +#define CONFIGURATION_BUF_SIZE (8 + FW_NAME_SIZE + FW_DESCRIPTION_SIZE) + +#define TIAUDIO_CMD_REG_WITE 1 +#define TIAUDIO_CMD_REG_READ 2 +#define TIAUDIO_CMD_DEBUG_ON 3 +#define TIAUDIO_CMD_PROGRAM 4 +#define TIAUDIO_CMD_CONFIGURATION 5 +#define TIAUDIO_CMD_FW_TIMESTAMP 6 +#define TIAUDIO_CMD_CALIBRATION 7 +#define TIAUDIO_CMD_SAMPLERATE 8 +#define TIAUDIO_CMD_BITRATE 9 +#define TIAUDIO_CMD_DACVOLUME 10 +#define TIAUDIO_CMD_SPEAKER 11 +#define TIAUDIO_CMD_FW_RELOAD 12 + +#define TAS2557_MAGIC_NUMBER 0x3235/* '2557' */ + +#define SMARTPA_SPK_DAC_VOLUME _IOWR(TAS2557_MAGIC_NUMBER, 1, unsigned long) +#define SMARTPA_SPK_POWER_ON _IOWR(TAS2557_MAGIC_NUMBER, 2, unsigned long) +#define SMARTPA_SPK_POWER_OFF _IOWR(TAS2557_MAGIC_NUMBER, 3, unsigned long) +#define SMARTPA_SPK_SWITCH_PROGRAM _IOWR(TAS2557_MAGIC_NUMBER, 4, unsigned long) +#define SMARTPA_SPK_SWITCH_CONFIGURATION _IOWR(TAS2557_MAGIC_NUMBER, 5, unsigned long) +#define SMARTPA_SPK_SWITCH_CALIBRATION _IOWR(TAS2557_MAGIC_NUMBER, 6, unsigned long) +#define SMARTPA_SPK_SET_SAMPLERATE _IOWR(TAS2557_MAGIC_NUMBER, 7, unsigned long) +#define SMARTPA_SPK_SET_BITRATE _IOWR(TAS2557_MAGIC_NUMBER, 8, unsigned long) + +int tas2557_register_misc(struct tas2557_priv *pTAS2557); +int tas2557_deregister_misc(struct tas2557_priv *pTAS2557); + +#endif /* _TAS2557_MISC_H */ diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557-regmap.c b/techpack/audio/asoc/codecs/tas2557/tas2557-regmap.c new file mode 100755 index 000000000000..dcd168a73d69 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557-regmap.c @@ -0,0 +1,936 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557-regmap.c +** +** Description: +** I2C driver with regmap for Texas Instruments TAS2557 High Performance 4W Smart Amplifier +** +** ============================================================================= +*/ + +#ifdef CONFIG_TAS2557_REGMAP + +#define DEBUG +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "tas2557.h" +#include "tas2557-core.h" +#include +#include +#ifdef CONFIG_TAS2557_CODEC +#include "tas2557-codec.h" +#endif + +#ifdef CONFIG_TAS2557_MISC +#include "tas2557-misc.h" +#endif + +#define ENABLE_TILOAD +#ifdef ENABLE_TILOAD +#include "tiload.h" +#endif +#include + +#define LOW_TEMPERATURE_GAIN 6 +#define LOW_TEMPERATURE_COUNTER 12 + +static int tas2557_change_book_page( + struct tas2557_priv *pTAS2557, + unsigned char nBook, + unsigned char nPage) +{ + int nResult = 0; + + if ((pTAS2557->mnCurrentBook == nBook) + && pTAS2557->mnCurrentPage == nPage) + goto end; + + if (pTAS2557->mnCurrentBook != nBook) { + nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, 0); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + goto end; + } + pTAS2557->mnCurrentPage = 0; + nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_REG, nBook); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + goto end; + } + pTAS2557->mnCurrentBook = nBook; + if (nPage != 0) { + nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + goto end; + } + pTAS2557->mnCurrentPage = nPage; + } + } else if (pTAS2557->mnCurrentPage != nPage) { + nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_BOOKCTL_PAGE, nPage); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + goto end; + } + pTAS2557->mnCurrentPage = nPage; + } + +end: + if (nResult < 0) + pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM; + else + pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM; + + return nResult; +} + +static int tas2557_dev_read( + struct tas2557_priv *pTAS2557, + unsigned int nRegister, + unsigned int *pValue) +{ + int nResult = 0; + unsigned int Value = 0; + + mutex_lock(&pTAS2557->dev_lock); + + if (pTAS2557->mbTILoadActive) { + if (!(nRegister & 0x80000000)) + goto end; /* let only reads from TILoad pass. */ + nRegister &= ~0x80000000; + + dev_dbg(pTAS2557->dev, "TiLoad R REG B[%d]P[%d]R[%d]\n", + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister), + TAS2557_PAGE_REG(nRegister)); + } + + nResult = tas2557_change_book_page(pTAS2557, + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister)); + if (nResult >= 0) { + nResult = regmap_read(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), &Value); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM; + goto end; + } else + pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM; + *pValue = Value; + } + +end: + + mutex_unlock(&pTAS2557->dev_lock); + return nResult; +} + +static int tas2557_dev_write( + struct tas2557_priv *pTAS2557, + unsigned int nRegister, + unsigned int nValue) +{ + int nResult = 0; + + mutex_lock(&pTAS2557->dev_lock); + if ((nRegister == 0xAFFEAFFE) && (nValue == 0xBABEBABE)) { + pTAS2557->mbTILoadActive = true; + goto end; + } + + if ((nRegister == 0xBABEBABE) && (nValue == 0xAFFEAFFE)) { + pTAS2557->mbTILoadActive = false; + goto end; + } + + if (pTAS2557->mbTILoadActive) { + if (!(nRegister & 0x80000000)) + goto end;/* let only writes from TILoad pass. */ + nRegister &= ~0x80000000; + + dev_dbg(pTAS2557->dev, "TiLoad W REG B[%d]P[%d]R[%d] =0x%x\n", + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister), + TAS2557_PAGE_REG(nRegister), + nValue); + } + + nResult = tas2557_change_book_page(pTAS2557, + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister)); + if (nResult >= 0) { + nResult = regmap_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nValue); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM; + } else + pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM; + } + +end: + + mutex_unlock(&pTAS2557->dev_lock); + + return nResult; +} + +static int tas2557_dev_bulk_read( + struct tas2557_priv *pTAS2557, + unsigned int nRegister, + u8 *pData, + unsigned int nLength) +{ + int nResult = 0; + int i; + + mutex_lock(&pTAS2557->dev_lock); + if (pTAS2557->mbTILoadActive) { + if (!(nRegister & 0x80000000)) + goto end; /* let only writes from TILoad pass. */ + + nRegister &= ~0x80000000; + dev_dbg(pTAS2557->dev, "TiLoad BR REG B[%d]P[%d]R[%d], count=%d\n", + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister), + TAS2557_PAGE_REG(nRegister), + nLength); + } + + nResult = tas2557_change_book_page(pTAS2557, + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister)); + if (nResult >= 0) { + #define STRIDE 4 + /* Read chunk bytes defined by STRIDE */ + for (i = 0; i < (nLength / STRIDE); i++) { + nResult = regmap_bulk_read(pTAS2557->mpRegmap, + TAS2557_PAGE_REG((nRegister + i*STRIDE)), + &pData[i*STRIDE], STRIDE); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM; + } else { + pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM; + } + } + + /* Read remaining bytes */ + if ((nLength % STRIDE) != 0) { + nResult = regmap_bulk_read(pTAS2557->mpRegmap, + TAS2557_PAGE_REG(nRegister + i*STRIDE), + &pData[i*STRIDE], (nLength % STRIDE)); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM; + } else { + pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM; + } + } + } + +end: + mutex_unlock(&pTAS2557->dev_lock); + return nResult; +} + +static int tas2557_dev_bulk_write( + struct tas2557_priv *pTAS2557, + unsigned int nRegister, + u8 *pData, + unsigned int nLength) +{ + int nResult = 0; + + mutex_lock(&pTAS2557->dev_lock); + if (pTAS2557->mbTILoadActive) { + if (!(nRegister & 0x80000000)) + goto end; /* let only writes from TILoad pass. */ + + nRegister &= ~0x80000000; + + dev_dbg(pTAS2557->dev, "TiLoad BW REG B[%d]P[%d]R[%d], count=%d\n", + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister), + TAS2557_PAGE_REG(nRegister), + nLength); + } + + nResult = tas2557_change_book_page( pTAS2557, + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister)); + if (nResult >= 0) { + nResult = regmap_bulk_write(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), pData, nLength); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM; + } else + pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM; + } + +end: + + mutex_unlock(&pTAS2557->dev_lock); + return nResult; +} + +static int tas2557_dev_update_bits( + struct tas2557_priv *pTAS2557, + unsigned int nRegister, + unsigned int nMask, + unsigned int nValue) +{ + int nResult = 0; + + mutex_lock(&pTAS2557->dev_lock); + + if (pTAS2557->mbTILoadActive) { + if (!(nRegister & 0x80000000)) + goto end; /* let only writes from TILoad pass. */ + + nRegister &= ~0x80000000; + dev_dbg(pTAS2557->dev, "TiLoad SB REG B[%d]P[%d]R[%d], mask=0x%x, value=0x%x\n", + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister), + TAS2557_PAGE_REG(nRegister), + nMask, nValue); + } + + nResult = tas2557_change_book_page( pTAS2557, + TAS2557_BOOK_ID(nRegister), + TAS2557_PAGE_ID(nRegister)); + if (nResult >= 0) { + nResult = regmap_update_bits(pTAS2557->mpRegmap, TAS2557_PAGE_REG(nRegister), nMask, nValue); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s, %d, I2C error %d\n", + __func__, __LINE__, nResult); + pTAS2557->mnErrCode |= ERROR_DEVA_I2C_COMM; + } else + pTAS2557->mnErrCode &= ~ERROR_DEVA_I2C_COMM; + } + +end: + mutex_unlock(&pTAS2557->dev_lock); + return nResult; +} + +void tas2557_clearIRQ(struct tas2557_priv *pTAS2557) +{ + unsigned int nValue; + int nResult = 0; + + nResult = pTAS2557->read(pTAS2557, TAS2557_FLAGS_1, &nValue); + if (nResult >= 0) + pTAS2557->read(pTAS2557, TAS2557_FLAGS_2, &nValue); + +} + + +void tas2557_enableIRQ(struct tas2557_priv *pTAS2557, bool enable) +{ + if (enable) { + if (!pTAS2557->mbIRQEnable) { + if (gpio_is_valid(pTAS2557->mnGpioINT)) { + enable_irq(pTAS2557->mnIRQ); + /* check after 10 ms */ + schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(10)); + pTAS2557->mbIRQEnable = true; + } + } + } else { + if (gpio_is_valid(pTAS2557->mnGpioINT)) + disable_irq_nosync(pTAS2557->mnIRQ); + pTAS2557->mbIRQEnable = false; + } +} + +static void tas2557_hw_reset(struct tas2557_priv *pTAS2557) +{ + if (gpio_is_valid(pTAS2557->mnResetGPIO)) { + gpio_direction_output(pTAS2557->mnResetGPIO, 0); + msleep(5); + gpio_direction_output(pTAS2557->mnResetGPIO, 1); + msleep(2); + } + + pTAS2557->mnCurrentBook = -1; + pTAS2557->mnCurrentPage = -1; + if (pTAS2557->mnErrCode) + dev_info(pTAS2557->dev, "before reset, ErrCode=0x%x\n", pTAS2557->mnErrCode); + pTAS2557->mnErrCode = 0; +} + +static void irq_work_routine(struct work_struct *work) +{ + int nResult = 0; + unsigned int nDevInt1Status = 0, nDevInt2Status = 0; + unsigned int nDevPowerUpFlag = 0; + int nCounter = 2; + struct tas2557_priv *pTAS2557 = + container_of(work, struct tas2557_priv, irq_work.work); + +#ifdef CONFIG_TAS2557_CODEC + mutex_lock(&pTAS2557->codec_lock); +#endif + +#ifdef CONFIG_TAS2557_MISC + mutex_lock(&pTAS2557->file_lock); +#endif + + if(pTAS2557->mnErrCode & ERROR_FAILSAFE) + goto program; + + if (pTAS2557->mbRuntimeSuspend) { + dev_info(pTAS2557->dev, "%s, Runtime Suspended\n", __func__); + goto end; + } + + if (!pTAS2557->mbPowerUp) { + dev_info(pTAS2557->dev, "%s, device not powered\n", __func__); + goto end; + } + + if ((!pTAS2557->mpFirmware->mnConfigurations) + || (!pTAS2557->mpFirmware->mnPrograms)) { + dev_info(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + goto end; + } + + nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_1, &nDevInt1Status); + if (nResult >= 0) + nResult = tas2557_dev_read(pTAS2557, TAS2557_FLAGS_2, &nDevInt2Status); + + if (nResult < 0) + goto program; + + if (((nDevInt1Status & 0xfc) != 0) || ((nDevInt2Status & 0x0c) != 0)) { + /* in case of INT_OC, INT_UV, INT_OT, INT_BO, INT_CL, INT_CLK1, INT_CLK2 */ + dev_err(pTAS2557->dev, "critical error: 0x%x, 0x%x\n", nDevInt1Status, nDevInt2Status); + if (nDevInt1Status & 0x80) { + pTAS2557->mnErrCode |= ERROR_OVER_CURRENT; + dev_err(pTAS2557->dev, "DEVA SPK over current!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_OVER_CURRENT; + + if (nDevInt1Status & 0x40) { + pTAS2557->mnErrCode |= ERROR_UNDER_VOLTAGE; + dev_err(pTAS2557->dev, "DEVA SPK under voltage!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_UNDER_VOLTAGE; + + if (nDevInt1Status & 0x20) { + pTAS2557->mnErrCode |= ERROR_CLK_HALT; + dev_err(pTAS2557->dev, "DEVA clk halted!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_CLK_HALT; + + if (nDevInt1Status & 0x10) { + pTAS2557->mnErrCode |= ERROR_DIE_OVERTEMP; + dev_err(pTAS2557->dev, "DEVA die over temperature!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_DIE_OVERTEMP; + + if (nDevInt1Status & 0x08) { + pTAS2557->mnErrCode |= ERROR_BROWNOUT; + dev_err(pTAS2557->dev, "DEVA brownout!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_BROWNOUT; + + if (nDevInt1Status & 0x04) { + pTAS2557->mnErrCode |= ERROR_CLK_LOST; + dev_err(pTAS2557->dev, "DEVA clock lost!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_CLK_LOST; + + if (nDevInt2Status & 0x08) { + pTAS2557->mnErrCode |= ERROR_CLK_DET1; + dev_err(pTAS2557->dev, "DEVA clk detection 1!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_CLK_DET1; + + if (nDevInt2Status & 0x04) { + pTAS2557->mnErrCode |= ERROR_CLK_DET2; + dev_err(pTAS2557->dev, "DEVA clk detection 2!\n"); + } else + pTAS2557->mnErrCode &= ~ERROR_CLK_DET2; + + goto program; + } else { + dev_dbg(pTAS2557->dev, "IRQ Status: 0x%x, 0x%x\n", nDevInt1Status, nDevInt2Status); + nCounter = 2; + while (nCounter > 0) { + nResult = tas2557_dev_read(pTAS2557, TAS2557_POWER_UP_FLAG_REG, &nDevPowerUpFlag); + if (nResult < 0) + goto program; + if ((nDevPowerUpFlag & 0xc0) == 0xc0) + break; + nCounter--; + if (nCounter > 0) { + /* in case check pow status just after power on TAS2557 */ + dev_dbg(pTAS2557->dev, "PowSts: 0x%x, check again after 10ms\n", + nDevPowerUpFlag); + msleep(10); + } + } + if ((nDevPowerUpFlag & 0xc0) != 0xc0) { + dev_err(pTAS2557->dev, "%s, Critical ERROR B[%d]_P[%d]_R[%d]= 0x%x\n", + __func__, + TAS2557_BOOK_ID(TAS2557_POWER_UP_FLAG_REG), + TAS2557_PAGE_ID(TAS2557_POWER_UP_FLAG_REG), + TAS2557_PAGE_REG(TAS2557_POWER_UP_FLAG_REG), + nDevPowerUpFlag); + pTAS2557->mnErrCode |= ERROR_CLASSD_PWR; + goto program; + } + pTAS2557->mnErrCode &= ~ERROR_CLASSD_PWR; + + dev_dbg(pTAS2557->dev, "%s: INT1=0x%x, INT2=0x%x; PowerUpFlag=0x%x\n", + __func__, nDevInt1Status, nDevInt2Status, nDevPowerUpFlag); + goto end; + } + +program: + /* hardware reset and reload */ + tas2557_set_program(pTAS2557, pTAS2557->mnCurrentProgram, pTAS2557->mnCurrentConfiguration); + +end: + +#ifdef CONFIG_TAS2557_MISC + mutex_unlock(&pTAS2557->file_lock); +#endif + +#ifdef CONFIG_TAS2557_CODEC + mutex_unlock(&pTAS2557->codec_lock); +#endif +} + +static irqreturn_t tas2557_irq_handler(int irq, void *dev_id) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)dev_id; + + tas2557_enableIRQ(pTAS2557, false); + /* get IRQ status after 100 ms */ + schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(100)); + return IRQ_HANDLED; +} + +static enum hrtimer_restart temperature_timer_func(struct hrtimer *timer) +{ + struct tas2557_priv *pTAS2557 = container_of(timer, struct tas2557_priv, mtimer); + + if (pTAS2557->mbPowerUp) { + schedule_work(&pTAS2557->mtimerwork); + schedule_delayed_work(&pTAS2557->irq_work, msecs_to_jiffies(1)); + } + return HRTIMER_NORESTART; +} + +static void timer_work_routine(struct work_struct *work) +{ + struct tas2557_priv *pTAS2557 = container_of(work, struct tas2557_priv, mtimerwork); + int nResult, nTemp, nActTemp; + struct TProgram *pProgram; + static int nAvg; + +#ifdef CONFIG_TAS2557_CODEC + mutex_lock(&pTAS2557->codec_lock); +#endif + +#ifdef CONFIG_TAS2557_MISC + mutex_lock(&pTAS2557->file_lock); +#endif + + if (pTAS2557->mbRuntimeSuspend) { + dev_info(pTAS2557->dev, "%s, Runtime Suspended\n", __func__); + goto end; + } + + if (!pTAS2557->mpFirmware->mnConfigurations) { + dev_info(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + goto end; + } + + pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]); + if (!pTAS2557->mbPowerUp + || (pProgram->mnAppMode != TAS2557_APP_TUNINGMODE)) { + dev_info(pTAS2557->dev, "%s, pass, Pow=%d, program=%s\n", + __func__, pTAS2557->mbPowerUp, pProgram->mpName); + goto end; + } + + nResult = tas2557_get_die_temperature(pTAS2557, &nTemp); + if (nResult >= 0) { + nActTemp = (int)(nTemp >> 23); + dev_dbg(pTAS2557->dev, "Die=0x%x, degree=%d\n", nTemp, nActTemp); + if (!pTAS2557->mnDieTvReadCounter) + nAvg = 0; + pTAS2557->mnDieTvReadCounter++; + nAvg += nActTemp; + if (!(pTAS2557->mnDieTvReadCounter % LOW_TEMPERATURE_COUNTER)) { + nAvg /= LOW_TEMPERATURE_COUNTER; + dev_dbg(pTAS2557->dev, "check : avg=%d\n", nAvg); + if (nAvg < -6) { + /* if Die temperature is below -6 degree C */ + if (pTAS2557->mnDevCurrentGain != LOW_TEMPERATURE_GAIN) { + nResult = tas2557_set_DAC_gain(pTAS2557, LOW_TEMPERATURE_GAIN); + if (nResult < 0) + goto end; + pTAS2557->mnDevCurrentGain = LOW_TEMPERATURE_GAIN; + dev_dbg(pTAS2557->dev, "LOW Temp: set gain to %d\n", LOW_TEMPERATURE_GAIN); + } + } else if (nAvg > 5) { + /* if Die temperature is above 5 degree C */ + if (pTAS2557->mnDevCurrentGain != pTAS2557->mnDevGain) { + nResult = tas2557_set_DAC_gain(pTAS2557, pTAS2557->mnDevGain); + if (nResult < 0) + goto end; + pTAS2557->mnDevCurrentGain = pTAS2557->mnDevGain; + dev_dbg(pTAS2557->dev, "LOW Temp: set gain to original\n"); + } + } + nAvg = 0; + } + + if (pTAS2557->mbPowerUp) + hrtimer_start(&pTAS2557->mtimer, + ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL); + } + +end: + +#ifdef CONFIG_TAS2557_MISC + mutex_unlock(&pTAS2557->file_lock); +#endif + +#ifdef CONFIG_TAS2557_CODEC + mutex_unlock(&pTAS2557->codec_lock); +#endif +} + +static int tas2557_runtime_suspend(struct tas2557_priv *pTAS2557) +{ + dev_dbg(pTAS2557->dev, "%s\n", __func__); + + pTAS2557->mbRuntimeSuspend = true; + + if (hrtimer_active(&pTAS2557->mtimer)) { + dev_dbg(pTAS2557->dev, "cancel die temp timer\n"); + hrtimer_cancel(&pTAS2557->mtimer); + } + if (work_pending(&pTAS2557->mtimerwork)) { + dev_dbg(pTAS2557->dev, "cancel timer work\n"); + cancel_work_sync(&pTAS2557->mtimerwork); + } + if (delayed_work_pending(&pTAS2557->irq_work)) { + dev_dbg(pTAS2557->dev, "cancel IRQ work\n"); + cancel_delayed_work_sync(&pTAS2557->irq_work); + } + + return 0; +} + +static int tas2557_runtime_resume(struct tas2557_priv *pTAS2557) +{ + struct TProgram *pProgram; + + dev_dbg(pTAS2557->dev, "%s\n", __func__); + if (!pTAS2557->mpFirmware->mpPrograms) { + dev_dbg(pTAS2557->dev, "%s, firmware not loaded\n", __func__); + goto end; + } + + if (pTAS2557->mnCurrentProgram >= pTAS2557->mpFirmware->mnPrograms) { + dev_err(pTAS2557->dev, "%s, firmware corrupted\n", __func__); + goto end; + } + + pProgram = &(pTAS2557->mpFirmware->mpPrograms[pTAS2557->mnCurrentProgram]); + if (pTAS2557->mbPowerUp && (pProgram->mnAppMode == TAS2557_APP_TUNINGMODE)) { + if (!hrtimer_active(&pTAS2557->mtimer)) { + dev_dbg(pTAS2557->dev, "%s, start Die Temp check timer\n", __func__); + pTAS2557->mnDieTvReadCounter = 0; + hrtimer_start(&pTAS2557->mtimer, + ns_to_ktime((u64)LOW_TEMPERATURE_CHECK_PERIOD * NSEC_PER_MSEC), HRTIMER_MODE_REL); + } + } + + pTAS2557->mbRuntimeSuspend = false; +end: + + return 0; +} + +static bool tas2557_volatile(struct device *pDev, unsigned int nRegister) +{ + return true; +} + +static bool tas2557_writeable(struct device *pDev, unsigned int nRegister) +{ + return true; +} + +static const struct regmap_config tas2557_i2c_regmap = { + .reg_bits = 8, + .val_bits = 8, + .writeable_reg = tas2557_writeable, + .volatile_reg = tas2557_volatile, + .cache_type = REGCACHE_NONE, + .max_register = 128, +}; + +/* tas2557_i2c_probe : +* platform dependent +* should implement hardware reset functionality +*/ +static int tas2557_i2c_probe(struct i2c_client *pClient, + const struct i2c_device_id *pID) +{ + struct tas2557_priv *pTAS2557; + int nResult = 0; + unsigned int nValue = 0; + const char *pFWName; + + dev_info(&pClient->dev, "%s enter\n", __func__); + + pTAS2557 = devm_kzalloc(&pClient->dev, sizeof(struct tas2557_priv), GFP_KERNEL); + if (!pTAS2557) { + nResult = -ENOMEM; + goto err; + } + + pTAS2557->dev = &pClient->dev; + i2c_set_clientdata(pClient, pTAS2557); + dev_set_drvdata(&pClient->dev, pTAS2557); + + pTAS2557->mpRegmap = devm_regmap_init_i2c(pClient, &tas2557_i2c_regmap); + if (IS_ERR(pTAS2557->mpRegmap)) { + nResult = PTR_ERR(pTAS2557->mpRegmap); + dev_err(&pClient->dev, "Failed to allocate register map: %d\n", + nResult); + goto err; + } + + if (pClient->dev.of_node) + tas2557_parse_dt(&pClient->dev, pTAS2557); + + if (gpio_is_valid(pTAS2557->mnResetGPIO)) { + nResult = gpio_request(pTAS2557->mnResetGPIO, "TAS2557-RESET"); + if (nResult < 0) { + dev_err(pTAS2557->dev, "%s: GPIO %d request error\n", + __func__, pTAS2557->mnResetGPIO); + goto err; + } + tas2557_hw_reset(pTAS2557); + } + + pTAS2557->read = tas2557_dev_read; + pTAS2557->write = tas2557_dev_write; + pTAS2557->bulk_read = tas2557_dev_bulk_read; + pTAS2557->bulk_write = tas2557_dev_bulk_write; + pTAS2557->update_bits = tas2557_dev_update_bits; + pTAS2557->enableIRQ = tas2557_enableIRQ; + pTAS2557->clearIRQ = tas2557_clearIRQ; + pTAS2557->set_config = tas2557_set_config; + pTAS2557->set_calibration = tas2557_set_calibration; + pTAS2557->hw_reset = tas2557_hw_reset; + pTAS2557->runtime_suspend = tas2557_runtime_suspend; + pTAS2557->runtime_resume = tas2557_runtime_resume; + pTAS2557->mnRestart = 0; + + mutex_init(&pTAS2557->dev_lock); + + /* Reset the chip */ + nResult = tas2557_dev_write(pTAS2557, TAS2557_SW_RESET_REG, 0x01); + if (nResult < 0) { + dev_err(&pClient->dev, "I2c fail, %d\n", nResult); + goto err; + } + + msleep(1); + { + + int i; + for(i =0; i<0x10; i++){ + tas2557_dev_read(pTAS2557, i, &nValue); + dev_err(pTAS2557->dev, "address:%x value: %x\n",i, nValue); + } + } + + /* Ti's original codes logic (which firmware binary selected) */ + tas2557_dev_read(pTAS2557, TAS2557_REV_PGID_REG, &nValue); + pTAS2557->mnPGID = nValue; + if (pTAS2557->mnPGID == TAS2557_PG_VERSION_2P1) { + dev_info(pTAS2557->dev, "PG2.1 Silicon found\n"); + pFWName = TAS2557_AAC_FW_NAME; + } else if (pTAS2557->mnPGID == TAS2557_PG_VERSION_1P0) { + dev_info(pTAS2557->dev, "PG1.0 Silicon found\n"); + pFWName = TAS2557_PG1P0_FW_NAME; + } else { + nResult = -ENOTSUPP; + dev_info(pTAS2557->dev, "unsupport Silicon 0x%x\n", pTAS2557->mnPGID); + goto err; + } + + /* Use our codecs logic to select Firmware binary */ + if (pTAS2557->mnSpkType == VENDOR_ID_GOER) + pFWName = TAS2557_GOER_FW_NAME; + else if (pTAS2557->mnSpkType == VENDOR_ID_AAC) + pFWName = TAS2557_AAC_FW_NAME; + else if (pTAS2557->mnSpkType == VENDOR_ID_SSI) + pFWName = TAS2557_SSI_FW_NAME; + else + pFWName = TAS2557_DEFAULT_FW_NAME; + + if (gpio_is_valid(pTAS2557->mnGpioINT)) { + nResult = gpio_request(pTAS2557->mnGpioINT, "TAS2557-IRQ"); + if (nResult < 0) { + dev_err(pTAS2557->dev, + "%s: GPIO %d request INT error\n", + __func__, pTAS2557->mnGpioINT); + goto err; + } + + gpio_direction_input(pTAS2557->mnGpioINT); + pTAS2557->mnIRQ = gpio_to_irq(pTAS2557->mnGpioINT); + dev_dbg(pTAS2557->dev, "irq = %d\n", pTAS2557->mnIRQ); + INIT_DELAYED_WORK(&pTAS2557->irq_work, irq_work_routine); + nResult = request_threaded_irq(pTAS2557->mnIRQ, tas2557_irq_handler, + NULL, IRQF_TRIGGER_HIGH | IRQF_ONESHOT, + pClient->name, pTAS2557); + if (nResult < 0) { + dev_err(pTAS2557->dev, + "request_irq failed, %d\n", nResult); + goto err; + } + disable_irq_nosync(pTAS2557->mnIRQ); + } + + pTAS2557->mpFirmware = devm_kzalloc(&pClient->dev, sizeof(struct TFirmware), GFP_KERNEL); + if (!pTAS2557->mpFirmware) { + nResult = -ENOMEM; + goto err; + } + + pTAS2557->mpCalFirmware = devm_kzalloc(&pClient->dev, sizeof(struct TFirmware), GFP_KERNEL); + if (!pTAS2557->mpCalFirmware) { + nResult = -ENOMEM; + goto err; + } + +#ifdef CONFIG_TAS2557_CODEC + mutex_init(&pTAS2557->codec_lock); + tas2557_register_codec(pTAS2557); +#endif + +#ifdef CONFIG_TAS2557_MISC + mutex_init(&pTAS2557->file_lock); + tas2557_register_misc(pTAS2557); +#endif + +#ifdef ENABLE_TILOAD + tiload_driver_init(pTAS2557); +#endif + dev_dbg(pTAS2557->dev, " firmware name %s\n", pFWName); + hrtimer_init(&pTAS2557->mtimer, CLOCK_MONOTONIC, HRTIMER_MODE_REL); + pTAS2557->mtimer.function = temperature_timer_func; + INIT_WORK(&pTAS2557->mtimerwork, timer_work_routine); + + nResult = request_firmware_nowait(THIS_MODULE, 1, pFWName, + pTAS2557->dev, GFP_KERNEL, pTAS2557, tas2557_fw_ready); + +err: + + return nResult; +} + +static int tas2557_i2c_remove(struct i2c_client *pClient) +{ + struct tas2557_priv *pTAS2557 = i2c_get_clientdata(pClient); + + dev_info(pTAS2557->dev, "%s\n", __func__); + +#ifdef CONFIG_TAS2557_CODEC + tas2557_deregister_codec(pTAS2557); + mutex_destroy(&pTAS2557->codec_lock); +#endif + +#ifdef CONFIG_TAS2557_MISC + tas2557_deregister_misc(pTAS2557); + mutex_destroy(&pTAS2557->file_lock); +#endif + + mutex_destroy(&pTAS2557->dev_lock); + return 0; +} + +static const struct i2c_device_id tas2557_i2c_id[] = { + {"tas2557", 0}, + {} +}; + +MODULE_DEVICE_TABLE(i2c, tas2557_i2c_id); + +#if defined(CONFIG_OF) +static const struct of_device_id tas2557_of_match[] = { + {.compatible = "ti,tas2557"}, + {}, +}; + +MODULE_DEVICE_TABLE(of, tas2557_of_match); +#endif + +static struct i2c_driver tas2557_i2c_driver = { + .driver = { + .name = "tas2557", + .owner = THIS_MODULE, +#if defined(CONFIG_OF) + .of_match_table = of_match_ptr(tas2557_of_match), +#endif + }, + .probe = tas2557_i2c_probe, + .remove = tas2557_i2c_remove, + .id_table = tas2557_i2c_id, +}; + +module_i2c_driver(tas2557_i2c_driver); + +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("TAS2557 I2C Smart Amplifier driver"); +MODULE_LICENSE("GPL v2"); + +#endif diff --git a/techpack/audio/asoc/codecs/tas2557/tas2557.h b/techpack/audio/asoc/codecs/tas2557/tas2557.h new file mode 100755 index 000000000000..e46bedc9fbab --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tas2557.h @@ -0,0 +1,495 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tas2557.h +** +** Description: +** definitions and data structures for TAS2557 Android Linux driver +** +** ============================================================================= +*/ + +#ifndef _TAS2557_H +#define _TAS2557_H + +#include +#include +#include + +/* Page Control Register */ +#define TAS2557_PAGECTL_REG 0 + +/* Book Control Register (available in page0 of each book) */ +#define TAS2557_BOOKCTL_PAGE 0 +#define TAS2557_BOOKCTL_REG 127 + +/* 0000 0000 0BBB BBBB BPPP PPPP PRRR RRRR */ + +#define TAS2557_REG(book, page, reg) ((((unsigned int)book * 256 * 128) + \ + ((unsigned int)page * 128)) + reg) + +#define TAS2557_BOOK_ID(reg) ((unsigned char)(reg / (256 * 128))) +#define TAS2557_PAGE_ID(reg) ((unsigned char)((reg % (256 * 128)) / 128)) +#define TAS2557_BOOK_REG(reg) ((unsigned char)(reg % (256 * 128))) +#define TAS2557_PAGE_REG(reg) ((unsigned char)((reg % (256 * 128)) % 128)) + +/* Book0, Page0 registers */ +#define TAS2557_SW_RESET_REG TAS2557_REG(0, 0, 1) + +#define TAS2557_REV_PGID_REG TAS2557_REG(0, 0, 3) +#define TAS2557_PG_VERSION_1P0 0x80 +#define TAS2557_PG_VERSION_2P0 0x90 +#define TAS2557_PG_VERSION_2P1 0xa0 + +#define TAS2557_POWER_CTRL1_REG TAS2557_REG(0, 0, 4) +#define TAS2557_POWER_CTRL2_REG TAS2557_REG(0, 0, 5) + +#define TAS2557_SPK_CTRL_REG TAS2557_REG(0, 0, 6) +/* B0P0R6 - TAS2557_SPK_CTRL_REG */ +#define TAS2557_DAC_GAIN_MASK (0xf << 3) +#define TAS2557_DAC_GAIN_SHIFT 0x03 + +#define TAS2557_MUTE_REG TAS2557_REG(0, 0, 7) +#define TAS2557_SNS_CTRL_REG TAS2557_REG(0, 0, 8) +#define TAS2557_ADC_INPUT_SEL_REG TAS2557_REG(0, 0, 9) +#define TAS2557_DBOOST_CTL_REG TAS2557_REG(0, 0, 10) +#define TAS2557_NONAME11_REG TAS2557_REG(0, 0, 11) +#define TAS2557_NONAME12_REG TAS2557_REG(0, 0, 12) +#define TAS2557_NONAME13_REG TAS2557_REG(0, 0, 13) +#define TAS2557_NONAME14_REG TAS2557_REG(0, 0, 14) +#define TAS2557_NONAME15_REG TAS2557_REG(0, 0, 15) +#define TAS2557_NONAME16_REG TAS2557_REG(0, 0, 16) +#define TAS2557_NONAME17_REG TAS2557_REG(0, 0, 17) +#define TAS2557_NONAME18_REG TAS2557_REG(0, 0, 18) +#define TAS2557_SAR_SAMPLING_TIME_REG TAS2557_REG(0, 0, 19) +#define TAS2557_SAR_ADC1_REG TAS2557_REG(0, 0, 20) +#define TAS2557_SAR_ADC2_REG TAS2557_REG(0, 0, 21) /* B0_P0_R0x15*/ +#define TAS2557_CRC_CHECKSUM_REG TAS2557_REG(0, 0, 32) +#define TAS2557_CRC_RESET_REG TAS2557_REG(0, 0, 33) +#define TAS2557_DSP_MODE_SELECT_REG TAS2557_REG(0, 0, 34) +#define TAS2557_SAFE_GUARD_REG TAS2557_REG(0, 0, 37) +#define TAS2557_ASI_CTL1_REG TAS2557_REG(0, 0, 42) +#define TAS2557_CLK_ERR_CTRL TAS2557_REG(0, 0, 44) /* B0_P0_R0x2c*/ +#define TAS2557_CLK_ERR_CTRL2 TAS2557_REG(0, 0, 45) /* B0_P0_R0x2d*/ +#define TAS2557_CLK_ERR_CTRL3 TAS2557_REG(0, 0, 46) /* B0_P0_R0x2e*/ +#define TAS2557_DBOOST_CFG_REG TAS2557_REG(0, 0, 52) +#define TAS2557_POWER_UP_FLAG_REG TAS2557_REG(0, 0, 100) +#define TAS2557_FLAGS_1 TAS2557_REG(0, 0, 104) /* B0_P0_R0x68*/ +#define TAS2557_FLAGS_2 TAS2557_REG(0, 0, 108) /* B0_P0_R0x6c*/ + +/* Book0, Page1 registers */ +#define TAS2557_ASI1_DAC_FORMAT_REG TAS2557_REG(0, 1, 1) +#define TAS2557_ASI1_ADC_FORMAT_REG TAS2557_REG(0, 1, 2) +#define TAS2557_ASI1_OFFSET1_REG TAS2557_REG(0, 1, 3) +#define TAS2557_ASI1_ADC_PATH_REG TAS2557_REG(0, 1, 7) +#define TAS2557_ASI1_DAC_BCLK_REG TAS2557_REG(0, 1, 8) +#define TAS2557_ASI1_DAC_WCLK_REG TAS2557_REG(0, 1, 9) +#define TAS2557_ASI1_ADC_BCLK_REG TAS2557_REG(0, 1, 10) +#define TAS2557_ASI1_ADC_WCLK_REG TAS2557_REG(0, 1, 11) +#define TAS2557_ASI1_DIN_DOUT_MUX_REG TAS2557_REG(0, 1, 12) +#define TAS2557_ASI1_BDIV_CLK_SEL_REG TAS2557_REG(0, 1, 13) +#define TAS2557_ASI1_BDIV_CLK_RATIO_REG TAS2557_REG(0, 1, 14) +#define TAS2557_ASI1_WDIV_CLK_RATIO_REG TAS2557_REG(0, 1, 15) +#define TAS2557_ASI1_DAC_CLKOUT_REG TAS2557_REG(0, 1, 16) +#define TAS2557_ASI1_ADC_CLKOUT_REG TAS2557_REG(0, 1, 17) +#define TAS2557_ASI2_DAC_FORMAT_REG TAS2557_REG(0, 1, 21) +#define TAS2557_ASI2_ADC_FORMAT_REG TAS2557_REG(0, 1, 22) +#define TAS2557_ASI2_OFFSET1_REG TAS2557_REG(0, 1, 23) +#define TAS2557_ASI2_ADC_PATH_REG TAS2557_REG(0, 1, 27) +#define TAS2557_ASI2_DAC_BCLK_REG TAS2557_REG(0, 1, 28) +#define TAS2557_ASI2_DAC_WCLK_REG TAS2557_REG(0, 1, 29) +#define TAS2557_ASI2_ADC_BCLK_REG TAS2557_REG(0, 1, 30) +#define TAS2557_ASI2_ADC_WCLK_REG TAS2557_REG(0, 1, 31) +#define TAS2557_ASI2_DIN_DOUT_MUX_REG TAS2557_REG(0, 1, 32) +#define TAS2557_ASI2_BDIV_CLK_SEL_REG TAS2557_REG(0, 1, 33) +#define TAS2557_ASI2_BDIV_CLK_RATIO_REG TAS2557_REG(0, 1, 34) +#define TAS2557_ASI2_WDIV_CLK_RATIO_REG TAS2557_REG(0, 1, 35) +#define TAS2557_ASI2_DAC_CLKOUT_REG TAS2557_REG(0, 1, 36) +#define TAS2557_ASI2_ADC_CLKOUT_REG TAS2557_REG(0, 1, 37) +#define TAS2557_GPIO1_PIN_REG TAS2557_REG(0, 1, 61) /*B0_P1_R0x3d */ +#define TAS2557_GPIO2_PIN_REG TAS2557_REG(0, 1, 62) /*B0_P1_R0x3e */ +#define TAS2557_GPIO3_PIN_REG TAS2557_REG(0, 1, 63) /*B0_P1_R0x3f */ +#define TAS2557_GPIO4_PIN_REG TAS2557_REG(0, 1, 64) /*B0_P1_R0x40 */ +#define TAS2557_GPIO5_PIN_REG TAS2557_REG(0, 1, 65) +#define TAS2557_GPIO6_PIN_REG TAS2557_REG(0, 1, 66) +#define TAS2557_GPIO7_PIN_REG TAS2557_REG(0, 1, 67) +#define TAS2557_GPIO8_PIN_REG TAS2557_REG(0, 1, 68) +#define TAS2557_GPIO9_PIN_REG TAS2557_REG(0, 1, 69) +#define TAS2557_GPIO10_PIN_REG TAS2557_REG(0, 1, 70) +#define TAS2557_GPI_PIN_REG TAS2557_REG(0, 1, 77) /*B0_P1_R0x4d */ +#define TAS2557_GPIO_HIZ_CTRL1_REG TAS2557_REG(0, 1, 79) +#define TAS2557_GPIO_HIZ_CTRL2_REG TAS2557_REG(0, 1, 80) /*B0_P1_R0x50 */ +#define TAS2557_GPIO_HIZ_CTRL3_REG TAS2557_REG(0, 1, 81) +#define TAS2557_GPIO_HIZ_CTRL4_REG TAS2557_REG(0, 1, 82) +#define TAS2557_GPIO_HIZ_CTRL5_REG TAS2557_REG(0, 1, 83) +#define TAS2557_BIT_BANG_CTRL_REG TAS2557_REG(0, 1, 87) +#define TAS2557_BIT_BANG_OUT1_REG TAS2557_REG(0, 1, 88) +#define TAS2557_BIT_BANG_OUT2_REG TAS2557_REG(0, 1, 89) +#define TAS2557_BIT_BANG_IN1_REG TAS2557_REG(0, 1, 90) +#define TAS2557_BIT_BANG_IN2_REG TAS2557_REG(0, 1, 91) +#define TAS2557_BIT_BANG_IN3_REG TAS2557_REG(0, 1, 92) +#define TAS2557_PDM_IN_CLK_REG TAS2557_REG(0, 1, 94) +#define TAS2557_PDM_IN_PIN_REG TAS2557_REG(0, 1, 95) +#define TAS2557_ASIM_IFACE1_REG TAS2557_REG(0, 1, 98) +#define TAS2557_ASIM_FORMAT_REG TAS2557_REG(0, 1, 99) +#define TAS2557_ASIM_IFACE3_REG TAS2557_REG(0, 1, 100) +#define TAS2557_ASIM_IFACE4_REG TAS2557_REG(0, 1, 101) +#define TAS2557_ASIM_IFACE5_REG TAS2557_REG(0, 1, 102) +#define TAS2557_ASIM_IFACE6_REG TAS2557_REG(0, 1, 103) +#define TAS2557_ASIM_IFACE7_REG TAS2557_REG(0, 1, 104) +#define TAS2557_ASIM_IFACE8_REG TAS2557_REG(0, 1, 105) +#define TAS2557_CLK_HALT_REG TAS2557_REG(0, 1, 106) /* B0_P1_R0x6a */ +#define TAS2557_INT_GEN1_REG TAS2557_REG(0, 1, 108) /* B0_P1_R0x6c */ +#define TAS2557_INT_GEN2_REG TAS2557_REG(0, 1, 109) /* B0_P1_R0x6d */ +#define TAS2557_INT_GEN3_REG TAS2557_REG(0, 1, 110) /* B0_P1_R0x6e */ +#define TAS2557_INT_GEN4_REG TAS2557_REG(0, 1, 111) /* B0_P1_R0x6f */ +#define TAS2557_INT_MODE_REG TAS2557_REG(0, 1, 114) /* B0_P1_R0x72 */ +#define TAS2557_MAIN_CLKIN_REG TAS2557_REG(0, 1, 115) +#define TAS2557_PLL_CLKIN_REG TAS2557_REG(0, 1, 116) +#define TAS2557_CLKOUT_MUX_REG TAS2557_REG(0, 1, 117) +#define TAS2557_CLKOUT_CDIV_REG TAS2557_REG(0, 1, 118) +#define TAS2557_HACK_GP01_REG TAS2557_REG(0, 1, 122) + +#define TAS2557_HACK01_REG TAS2557_REG(0, 2, 10) + +#define TAS2557_ISENSE_THRESHOLD TAS2557_REG(0, 50, 104) +#define TAS2557_BOOSTON_EFFICIENCY TAS2557_REG(0, 51, 16) +#define TAS2557_BOOSTOFF_EFFICIENCY TAS2557_REG(0, 51, 20) +#define TAS2557_BOOST_HEADROOM TAS2557_REG(0, 51, 24) +#define TAS2557_THERMAL_FOLDBACK_REG TAS2557_REG(0, 51, 100) + +#define TAS2557_SA_PG2P1_CHL_CTRL_REG TAS2557_REG(0, 53, 20) /* B0_P0x35_R0x14 */ +#define TAS2557_SA_COEFF_SWAP_REG TAS2557_REG(0, 53, 44) /* B0_P0x35_R0x2c */ + +#define TAS2557_SA_PG1P0_CHL_CTRL_REG TAS2557_REG(0, 58, 120) /* B0_P0x3a_R0x78 */ + +#define TAS2557_TEST_MODE_REG TAS2557_REG(0, 253, 13) /* B0_P0xfd_R0x0d */ +#define TAS2557_BROADCAST_REG TAS2557_REG(0, 253, 54) /* B0_P0xfd_R0x36 */ +#define TAS2557_CRYPTIC_REG TAS2557_REG(0, 253, 71) +#define TAS2557_PG2P1_CALI_R0_REG TAS2557_REG(0x8c, 0x2f, 0x40) +#define TAS2557_PG1P0_CALI_R0_REG TAS2557_REG(0x8c, 0x2f, 0x28) +#define TAS2557_PG2P1_CALI_T_REG TAS2557_REG(0x8c, 0x30, 0x20) +#define TAS2557_PG1P0_CALI_T_REG TAS2557_REG(0x8c, 0x30, 0x08) + +#define TAS2557_DAC_INTERPOL_REG TAS2557_REG(100, 0, 1) +#define TAS2557_SOFT_MUTE_REG TAS2557_REG(100, 0, 7) +#define TAS2557_PLL_P_VAL_REG TAS2557_REG(100, 0, 27) +#define TAS2557_PLL_J_VAL_REG TAS2557_REG(100, 0, 28) +#define TAS2557_PLL_D_VAL_MSB_REG TAS2557_REG(100, 0, 29) +#define TAS2557_PLL_D_VAL_LSB_REG TAS2557_REG(100, 0, 30) +#define TAS2557_CLK_MISC_REG TAS2557_REG(100, 0, 31) +#define TAS2557_PLL_N_VAL_REG TAS2557_REG(100, 0, 32) +#define TAS2557_DAC_MADC_VAL_REG TAS2557_REG(100, 0, 33) +#define TAS2557_ISENSE_DIV_REG TAS2557_REG(100, 0, 42) +#define TAS2557_RAMP_CLK_DIV_MSB_REG TAS2557_REG(100, 0, 43) +#define TAS2557_RAMP_CLK_DIV_LSB_REG TAS2557_REG(100, 0, 44) + +#define TAS2557_DIE_TEMP_REG TAS2557_REG(130, 2, 124) /* B0x82_P0x02_R0x7C */ + +/* Bits */ +/* B0P0R4 - TAS2557_POWER_CTRL1_REG */ +#define TAS2557_SW_SHUTDOWN (0x1 << 0) +#define TAS2557_MADC_POWER_UP (0x1 << 3) +#define TAS2557_MDAC_POWER_UP (0x1 << 4) +#define TAS2557_NDIV_POWER_UP (0x1 << 5) +#define TAS2557_PLL_POWER_UP (0x1 << 6) +#define TAS2557_DSP_POWER_UP (0x1 << 7) + +/* B0P0R5 - TAS2557_POWER_CTRL2_REG */ +#define TAS2557_VSENSE_ENABLE (0x1 << 0) +#define TAS2557_ISENSE_ENABLE (0x1 << 1) +#define TAS2557_BOOST_ENABLE (0x1 << 5) +#define TAS2557_CLASSD_ENABLE (0x1 << 7) + +/* B0P0R7 - TAS2557_MUTE_REG */ +#define TAS2557_CLASSD_MUTE (0x1 << 0) +#define TAS2557_ISENSE_MUTE (0x1 << 1) + +/* B0P253R13 - TAS2557_TEST_MODE_REG */ +#define TAS2557_TEST_MODE_ENABLE (13) +#define TAS2557_TEST_MODE_MASK (0xf << 0) + +/* B0P253R71 - TAS2557_CRYPTIC_REG */ +#define TAS2557_OSC_TRIM_CAP(x) ((x & 0x3f) << 0) +#define TAS2557_DISABLE_ENCRYPTION (0x1 << 6) +#define TAS2557_SL_COMP (0x1 << 7) + +/* B0P1R115/6 - TAS2557_MAIN/PLL_CLKIN_REG */ +#define TAS2557_XXX_CLKIN_GPIO1 (0) +#define TAS2557_XXX_CLKIN_GPIO2 (1) +#define TAS2557_XXX_CLKIN_GPIO3 (2) +#define TAS2557_XXX_CLKIN_GPIO4 (3) +#define TAS2557_XXX_CLKIN_GPIO5 (4) +#define TAS2557_XXX_CLKIN_GPIO6 (5) +#define TAS2557_XXX_CLKIN_GPIO7 (6) +#define TAS2557_XXX_CLKIN_GPIO8 (7) +#define TAS2557_XXX_CLKIN_GPIO9 (8) +#define TAS2557_XXX_CLKIN_GPIO10 (9) +#define TAS2557_XXX_CLKIN_GPI1 (12) +#define TAS2557_XXX_CLKIN_GPI2 (13) +#define TAS2557_XXX_CLKIN_GPI3 (14) +#define TAS2557_NDIV_CLKIN_PLL (15) +#define TAS2557_PLL_CLKIN_INT_OSC (15) + +#define TAS2557_MCLK_CLKIN_SRC_GPIO1 (0) +#define TAS2557_MCLK_CLKIN_SRC_GPIO2 (1) +#define TAS2557_MCLK_CLKIN_SRC_GPIO3 (2) +#define TAS2557_MCLK_CLKIN_SRC_GPIO4 (3) +#define TAS2557_MCLK_CLKIN_SRC_GPIO5 (4) +#define TAS2557_MCLK_CLKIN_SRC_GPIO6 (5) +#define TAS2557_MCLK_CLKIN_SRC_GPIO7 (6) +#define TAS2557_MCLK_CLKIN_SRC_GPIO8 (7) +#define TAS2557_MCLK_CLKIN_SRC_GPIO9 (8) +#define TAS2557_MCLK_CLKIN_SRC_GPIO10 (9) +#define TAS2557_MCLK_CLKIN_SRC_GPI1 (12) +#define TAS2557_MCLK_CLKIN_SRC_GPI2 (13) +#define TAS2557_MCLK_CLKIN_SRC_GPI3 (14) + +#define TAS2557_FORMAT_I2S (0x0 << 5) +#define TAS2557_FORMAT_DSP (0x1 << 5) +#define TAS2557_FORMAT_RIGHT_J (0x2 << 5) +#define TAS2557_FORMAT_LEFT_J (0x3 << 5) +#define TAS2557_FORMAT_MONO_PCM (0x4 << 5) +#define TAS2557_FORMAT_MASK (0x7 << 5) + +#define TAS2557_WORDLENGTH_16BIT (0x0 << 3) +#define TAS2557_WORDLENGTH_20BIT (0x1 << 3) +#define TAS2557_WORDLENGTH_24BIT (0x2 << 3) +#define TAS2557_WORDLENGTH_32BIT (0x3 << 3) +#define TAS2557_WORDLENGTH_MASK TAS2557_WORDLENGTH_32BIT + +/* B100P0R7 - TAS2557_SOFT_MUTE_REG */ +#define TAS2557_PDM_SOFT_MUTE (0x1 << 0) +#define TAS2557_VSENSE_SOFT_MUTE (0x1 << 1) +#define TAS2557_ISENSE_SOFT_MUTE (0x1 << 2) +#define TAS2557_CLASSD_SOFT_MUTE (0x1 << 3) + +/* B100P0R27 - TAS2557_PLL_P_VAL_REG */ +#define TAS2557_PLL_P_VAL_MASK (0x3f << 0) + +/* B100P0R28 - TAS2557_PLL_J_VAL_REG */ +#define TAS2557_PLL_J_VAL_MASK ((unsigned int) (0x7f << 0)) +#define TAS2557_PLL_J_VAL_MASKX 0x00 + +/* B100P0R29-30 - TAS2557_PLL_D_VAL_MSB/LSB_REG */ +#define TAS2557_PLL_D_MSB_VAL(x) ((x >> 8) & 0x3f) +#define TAS2557_PLL_D_LSB_VAL(x) (x & 0xff) + +/* B100P0R31 - TAS2557_CLK_MISC_REG */ +#define TAS2557_DSP_CLK_FROM_PLL (0x1 << 5) + +#define TAS2557_AAC_FW_NAME "tas2557_uCDSP_aac.bin" +#define TAS2557_GOER_FW_NAME "tas2557_uCDSP_goer.bin" +#define TAS2557_SSI_FW_NAME "tas2557_uCDSP_ssi.bin" +#define TAS2557_DEFAULT_FW_NAME "tas2557_uCDSP.bin" + +#define TAS2557_PG1P0_FW_NAME "tas2557_pg1p0_uCDSP.bin" + +#define TAS2557_APP_ROM1MODE 0 +#define TAS2557_APP_ROM2MODE 1 +#define TAS2557_APP_TUNINGMODE 2 +#define TAS2557_APP_ROM1_96KHZ 3 +#define TAS2557_APP_ROM2_96KHZ 4 +#define TAS2557_APP_RAMMODE 5 + +#define TAS2557_BOOST_OFF 0 +#define TAS2557_BOOST_DEVA 1 +#define TAS2557_BOOST_DEVB 2 +#define TAS2557_BOOST_BOTH 3 + +#define ERROR_NONE 0x00000000 +#define ERROR_PLL_ABSENT 0x00000001 +#define ERROR_DEVA_I2C_COMM 0x00000002 +#define ERROR_PRAM_CRCCHK 0x00000008 +#define ERROR_YRAM_CRCCHK 0x00000010 +#define ERROR_CLK_DET2 0x00000020 +#define ERROR_CLK_DET1 0x00000040 +#define ERROR_CLK_LOST 0x00000080 +#define ERROR_BROWNOUT 0x00000100 +#define ERROR_DIE_OVERTEMP 0x00000200 +#define ERROR_CLK_HALT 0x00000400 +#define ERROR_UNDER_VOLTAGE 0x00000800 +#define ERROR_OVER_CURRENT 0x00001000 +#define ERROR_CLASSD_PWR 0x00002000 +#define ERROR_SAFE_GUARD 0x00004000 +#define ERROR_FAILSAFE 0x40000000 + +struct TBlock { + unsigned int mnType; + unsigned char mbPChkSumPresent; + unsigned char mnPChkSum; + unsigned char mbYChkSumPresent; + unsigned char mnYChkSum; + unsigned int mnCommands; + unsigned char *mpData; +}; + +struct TData { + char mpName[64]; + char *mpDescription; + unsigned int mnBlocks; + struct TBlock *mpBlocks; +}; + +struct TProgram { + char mpName[64]; + char *mpDescription; + unsigned char mnAppMode; + unsigned short mnBoost; + struct TData mData; +}; + +struct TPLL { + char mpName[64]; + char *mpDescription; + struct TBlock mBlock; +}; + +struct TConfiguration { + char mpName[64]; + char *mpDescription; + unsigned int mnDevices; + unsigned int mnProgram; + unsigned int mnPLL; + unsigned int mnSamplingRate; + unsigned char mnPLLSrc; + unsigned int mnPLLSrcRate; + struct TData mData; +}; + +struct TCalibration { + char mpName[64]; + char *mpDescription; + unsigned int mnProgram; + unsigned int mnConfiguration; + struct TData mData; +}; + +struct TFirmware { + unsigned int mnFWSize; + unsigned int mnChecksum; + unsigned int mnPPCVersion; + unsigned int mnFWVersion; + unsigned int mnDriverVersion; + unsigned int mnTimeStamp; + char mpDDCName[64]; + char *mpDescription; + unsigned int mnDeviceFamily; + unsigned int mnDevice; + unsigned int mnPLLs; + struct TPLL *mpPLLs; + unsigned int mnPrograms; + struct TProgram *mpPrograms; + unsigned int mnConfigurations; + struct TConfiguration *mpConfigurations; + unsigned int mnCalibrations; + struct TCalibration *mpCalibrations; +}; + +struct tas2557_register { + int book; + int page; + int reg; +}; + +struct tas2557_priv { + struct device *dev; + struct regmap *mpRegmap; + int mnPGID; + int mnResetGPIO; + struct mutex dev_lock; + struct TFirmware *mpFirmware; + struct TFirmware *mpCalFirmware; + unsigned int mnCurrentProgram; + unsigned int mnCurrentSampleRate; + unsigned int mnNewConfiguration; + unsigned int mnCurrentConfiguration; + unsigned int mnCurrentCalibration; + unsigned char mnCurrentBook; + unsigned char mnCurrentPage; + bool mbTILoadActive; + bool mbPowerUp; + bool mbMute; + bool mbLoadConfigurationPrePowerUp; + bool mbLoadCalibrationPostPowerUp; + bool mbCalibrationLoaded; + int (*read)(struct tas2557_priv *pTAS2557, + unsigned int reg, + unsigned int *pValue); + int (*write)(struct tas2557_priv *pTAS2557, + unsigned int reg, + unsigned int Value); + int (*bulk_read)(struct tas2557_priv *pTAS2557, + unsigned int reg, + unsigned char *pData, + unsigned int len); + int (*bulk_write)(struct tas2557_priv *pTAS2557, + unsigned int reg, + unsigned char *pData, + unsigned int len); + int (*update_bits)(struct tas2557_priv *pTAS2557, + unsigned int reg, + unsigned int mask, + unsigned int value); + int (*set_config)(struct tas2557_priv *pTAS2557, + int config); + int (*set_calibration)(struct tas2557_priv *pTAS2557, + int calibration); + void (*clearIRQ)(struct tas2557_priv *pTAS2557); + void (*enableIRQ)(struct tas2557_priv *pTAS2557, bool enable); + void (*hw_reset)(struct tas2557_priv *pTAS2557); + /* device is working, but system is suspended */ + int (*runtime_suspend)(struct tas2557_priv *pTAS2557); + int (*runtime_resume)(struct tas2557_priv *pTAS2557); + + int mnGpioINT; + struct delayed_work irq_work; + unsigned int mnIRQ; + bool mbIRQEnable; + unsigned char mnI2SBits; + + + /* for low temperature check */ + unsigned int mnDevGain; + unsigned int mnDevCurrentGain; + unsigned int mnDieTvReadCounter; + struct hrtimer mtimer; + struct work_struct mtimerwork; + + /* device is working, but system is suspended */ + bool mbRuntimeSuspend; + + unsigned int mnErrCode; + unsigned int mnRestart; + + /* for configurations with maximum TLimit 0x7fffffff, + * bypass calibration update, usually used in factory test + */ + bool mbBypassTMax; + +#ifdef CONFIG_TAS2557_CODEC + struct mutex codec_lock; +#endif + +#ifdef CONFIG_TAS2557_MISC + int mnDBGCmd; + int mnCurrentReg; + struct mutex file_lock; +#endif + int mnSpkType; + struct device_node *spk_id_gpio_p; + + +}; + +#endif /* _TAS2557_H */ diff --git a/techpack/audio/asoc/codecs/tas2557/tiload.c b/techpack/audio/asoc/codecs/tas2557/tiload.c new file mode 100644 index 000000000000..4cf0ddfa1879 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tiload.c @@ -0,0 +1,428 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tiload.c +** +** Description: +** utility for TAS2557 Android in-system tuning +** +** ============================================================================= +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tiload.h" + +/* enable debug prints in the driver */ +#define DEBUG + +static struct cdev *tiload_cdev; +static int tiload_major; /* Dynamic allocation of Mjr No. */ +static int tiload_opened; /* Dynamic allocation of Mjr No. */ +static struct tas2557_priv *g_TAS2557; +struct class *tiload_class; +static unsigned int magic_num; + +static char gPage; +static char gBook; +/******************************** Debug section *****************************/ + + +/*---------------------------------------------------------------------------- + * Function : tiload_open + * + * Purpose : open method for tiload programming interface + *---------------------------------------------------------------------------- + */ +static int tiload_open(struct inode *in, struct file *filp) +{ + struct tas2557_priv *pTAS2557 = g_TAS2557; + + dev_info(pTAS2557->dev, "%s\n", __func__); + + if (tiload_opened) { + dev_info(pTAS2557->dev, "%s device is already opened\n", "tiload"); + return -EINVAL; + } + filp->private_data = (void *)pTAS2557; + tiload_opened++; + return 0; +} + +/*---------------------------------------------------------------------------- + * Function : tiload_release + * + * Purpose : close method for tiload programming interface + *---------------------------------------------------------------------------- + */ +static int tiload_release(struct inode *in, struct file *filp) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data; + + dev_info(pTAS2557->dev, "%s\n", __func__); + filp->private_data = NULL; + tiload_opened--; + return 0; +} + +#define MAX_LENGTH 128 +/*---------------------------------------------------------------------------- + * Function : tiload_read + * + * Purpose : read from codec + *---------------------------------------------------------------------------- + */ +static ssize_t tiload_read(struct file *filp, char __user *buf, + size_t count, loff_t *offset) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data; + char *rd_data; + unsigned int nCompositeRegister = 0, Value = 0; + char reg_addr; + size_t size; + int ret = 0; +#ifdef DEBUG + /* int i; */ +#endif + + dev_info(pTAS2557->dev, "%s\n", __func__); + if (count > MAX_LENGTH) { + dev_err(pTAS2557->dev, "Max %d bytes can be read\n", MAX_LENGTH); + return -EINVAL; + } + + /* copy register address from user space */ + size = copy_from_user(®_addr, buf, 1); + if (size != 0) { + dev_err(pTAS2557->dev, "read: copy_from_user failure\n"); + return -EINVAL; + } + + size = count; + + rd_data = kmalloc(MAX_LENGTH + 1, GFP_KERNEL | GFP_DMA); + + if(rd_data == NULL) { + dev_err(pTAS2557->dev, "kmalloc fail \n"); + return -EINVAL; + } + + nCompositeRegister = BPR_REG(gBook, gPage, reg_addr); + if (count == 1) { + ret = + pTAS2557->read(pTAS2557, 0x80000000 | nCompositeRegister, &Value); + if (ret >= 0) + rd_data[0] = (char) Value; + } else if (count > 1) { + ret = + pTAS2557->bulk_read(pTAS2557, 0x80000000 | nCompositeRegister, + rd_data, size); + } + if (ret < 0) + dev_err(pTAS2557->dev, "%s, %d, ret=%d, count=%zu error happen!\n", + __func__, __LINE__, ret, count); + +#ifdef DEBUG + dev_info(pTAS2557->dev, "read size = %d, reg_addr= %x , count = %d\n", + (int) size, reg_addr, (int) count); +/* for (i = 0; i < (int) size; i++) { +* dev_dbg(pTAS2557->dev, "rd_data[%d]=%x\n", i, rd_data[i]); +* } +*/ +#endif + if (size != count) + dev_err(pTAS2557->dev, "read %d registers from the codec\n", (int) size); + + if (copy_to_user(buf, rd_data, size) != 0) { + dev_err(pTAS2557->dev, "copy_to_user failed\n"); + kfree(rd_data); + return -EINVAL; + } + + kfree(rd_data); + return size; +} + +/* + *---------------------------------------------------------------------------- + * Function : tiload_write + * + * Purpose : write to codec + *---------------------------------------------------------------------------- + */ +static ssize_t tiload_write(struct file *filp, const char __user *buf, + size_t count, loff_t *offset) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data; + char *wr_data; + char *pData; + size_t size; + unsigned int nCompositeRegister = 0; + unsigned int nRegister; + int ret = 0; +#ifdef DEBUG + /* int i; */ +#endif + dev_info(pTAS2557->dev, "%s\n", __func__); + + if (count > MAX_LENGTH) { + dev_err(pTAS2557->dev, "Max %d bytes can be read\n", MAX_LENGTH); + return -EINVAL; + } + + wr_data = kmalloc(MAX_LENGTH + 1, GFP_KERNEL | GFP_DMA); + if(wr_data == NULL) { + dev_err(pTAS2557->dev, "kmalloc fail \n"); + return -EINVAL; + } + pData = wr_data; + + /* copy buffer from user space */ + size = copy_from_user(wr_data, buf, count); + if (size != 0) { + dev_err(pTAS2557->dev, "copy_from_user failure %d\n", (int) size); + kfree(wr_data); + return -EINVAL; + } +#ifdef DEBUG + dev_info(pTAS2557->dev, "write size = %zu\n", count); +/* for (i = 0; i < (int) count; i++) { +* dev_info(pTAS2557->dev, "wr_data[%d]=%x\n", i, wr_data[i]); +* } +*/ +#endif + nRegister = wr_data[0]; + size = count; + if ((nRegister == 127) && (gPage == 0)) { + gBook = wr_data[1]; + kfree(wr_data); + return size; + } + + if (nRegister == 0) { + gPage = wr_data[1]; + pData++; + count--; + } + + nCompositeRegister = BPR_REG(gBook, gPage, nRegister); + if (count == 2) { + ret = + pTAS2557->write(pTAS2557, 0x80000000 | nCompositeRegister, + pData[1]); + } else if (count > 2) { + ret = + pTAS2557->bulk_write(pTAS2557, 0x80000000 | nCompositeRegister, + &pData[1], count - 1); + } + + if (ret < 0) + dev_err(pTAS2557->dev, "%s, %d, ret=%d, count=%zu, ERROR Happen\n", __func__, + __LINE__, ret, count); + kfree(wr_data); + return size; +} + +static void tiload_route_IO(struct tas2557_priv *pTAS2557, unsigned int bLock) +{ + if (bLock) + pTAS2557->write(pTAS2557, 0xAFFEAFFE, 0xBABEBABE); + else + pTAS2557->write(pTAS2557, 0xBABEBABE, 0xAFFEAFFE); +} + +static long tiload_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data; + long num = 0; + void __user *argp = (void __user *) arg; + int val; + struct BPR bpr; + + dev_info(pTAS2557->dev, "%s, cmd=0x%x\n", __func__, cmd); +/* if (_IOC_TYPE(cmd) != TILOAD_IOC_MAGIC) + * return -ENOTTY; + */ + + switch (cmd) { + case TILOAD_IOMAGICNUM_GET: + num = copy_to_user(argp, &magic_num, sizeof(int)); + break; + case TILOAD_IOMAGICNUM_SET: + num = copy_from_user(&magic_num, argp, sizeof(int)); + dev_info(pTAS2557->dev, "TILOAD_IOMAGICNUM_SET\n"); + tiload_route_IO(pTAS2557, magic_num); + break; + case TILOAD_BPR_READ: + break; + case TILOAD_BPR_WRITE: + num = copy_from_user(&bpr, argp, sizeof(struct BPR)); + dev_info(pTAS2557->dev, "TILOAD_BPR_WRITE: 0x%02X, 0x%02X, 0x%02X\n\r", bpr.nBook, + bpr.nPage, bpr.nRegister); + break; + case TILOAD_IOCTL_SET_CHL: + break; + case TILOAD_IOCTL_SET_CONFIG: + num = copy_from_user(&val, argp, sizeof(val)); + pTAS2557->set_config(pTAS2557, val); + break; + case TILOAD_IOCTL_SET_CALIBRATION: + num = copy_from_user(&val, argp, sizeof(val)); + pTAS2557->set_calibration(pTAS2557, val); + break; + default: + break; + } + return num; +} + +#ifdef CONFIG_COMPAT +static long tiload_compat_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct tas2557_priv *pTAS2557 = (struct tas2557_priv *)filp->private_data; + long nResult = 0; + + switch (cmd) { + case TILOAD_COMPAT_IOMAGICNUM_GET: + dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOMAGICNUM_GET=0x%x\n", + __func__, cmd); + nResult = tiload_ioctl(filp, TILOAD_IOMAGICNUM_GET, + (unsigned long) compat_ptr(arg)); + break; + + case TILOAD_COMPAT_IOMAGICNUM_SET: + dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOMAGICNUM_SET=0x%x\n", + __func__, cmd); + nResult = tiload_ioctl(filp, TILOAD_IOMAGICNUM_SET, + (unsigned long) compat_ptr(arg)); + break; + + case TILOAD_COMPAT_BPR_READ: + dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_BPR_READ=0x%x\n", + __func__, cmd); + nResult = tiload_ioctl(filp, TILOAD_BPR_READ, + (unsigned long) compat_ptr(arg)); + break; + + case TILOAD_COMPAT_BPR_WRITE: + dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_BPR_WRITE=0x%x\n", + __func__, cmd); + nResult = tiload_ioctl(filp, TILOAD_BPR_WRITE, + (unsigned long) compat_ptr(arg)); + break; + + case TILOAD_COMPAT_IOCTL_SET_CHL: + dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOCTL_SET_CHL=0x%x\n", + __func__, cmd); + nResult = tiload_ioctl(filp, TILOAD_IOCTL_SET_CHL, + (unsigned long) compat_ptr(arg)); + break; + + case TILOAD_COMPAT_IOCTL_SET_CONFIG: + dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOCTL_SET_CONFIG=0x%x\n", + __func__, cmd); + nResult = tiload_ioctl(filp, TILOAD_IOCTL_SET_CONFIG, + (unsigned long) compat_ptr(arg)); + break; + + case TILOAD_COMPAT_IOCTL_SET_CALIBRATION: + dev_info(pTAS2557->dev, "%s, TILOAD_COMPAT_IOCTL_SET_CALIBRATION=0x%x\n", + __func__, cmd); + nResult = tiload_ioctl(filp, TILOAD_IOCTL_SET_CALIBRATION, + (unsigned long) compat_ptr(arg)); + break; + + default: + dev_err(pTAS2557->dev, "%s, unsupport compat ioctl=0x%x\n", + __func__, cmd); + break; + } + + return nResult; +} +#endif + +/*********** File operations structure for tiload *************/ +static const struct file_operations tiload_fops = { + .owner = THIS_MODULE, + .open = tiload_open, + .release = tiload_release, + .read = tiload_read, + .write = tiload_write, + .unlocked_ioctl = tiload_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = tiload_compat_ioctl, +#endif +}; + +/*---------------------------------------------------------------------------- + * Function : tiload_driver_init + * + * Purpose : Register a char driver for dynamic tiload programming + *---------------------------------------------------------------------------- + */ +int tiload_driver_init(struct tas2557_priv *pTAS2557) +{ + int result; + dev_t dev = MKDEV(tiload_major, 0); + + g_TAS2557 = pTAS2557; + + dev_info(pTAS2557->dev, "%s\n", __func__); + + result = alloc_chrdev_region(&dev, 0, 1, DEVICE_NAME); + if (result < 0) { + dev_err(pTAS2557->dev, "cannot allocate major number %d\n", tiload_major); + return result; + } + tiload_class = class_create(THIS_MODULE, DEVICE_NAME); + tiload_major = MAJOR(dev); + dev_info(pTAS2557->dev, "allocated Major Number: %d\n", tiload_major); + + tiload_cdev = cdev_alloc(); + cdev_init(tiload_cdev, &tiload_fops); + tiload_cdev->owner = THIS_MODULE; + tiload_cdev->ops = &tiload_fops; + + if (device_create(tiload_class, NULL, dev, NULL, "tiload_node") == NULL) + dev_err(pTAS2557->dev, "Device creation failed\n"); + + if (cdev_add(tiload_cdev, dev, 1) < 0) { + dev_err(pTAS2557->dev, "tiload_driver: cdev_add failed\n"); + unregister_chrdev_region(dev, 1); + tiload_cdev = NULL; + return 1; + } + dev_info(pTAS2557->dev, "Registered TiLoad driver, Major number: %d\n", tiload_major); + /* class_device_create(tiload_class, NULL, dev, NULL, DEVICE_NAME, 0); */ + return 0; +} + +MODULE_AUTHOR("Texas Instruments Inc."); +MODULE_DESCRIPTION("Utility for TAS2557 Android in-system tuning"); +MODULE_LICENSE("GPL v2"); diff --git a/techpack/audio/asoc/codecs/tas2557/tiload.h b/techpack/audio/asoc/codecs/tas2557/tiload.h new file mode 100644 index 000000000000..7468acfa3964 --- /dev/null +++ b/techpack/audio/asoc/codecs/tas2557/tiload.h @@ -0,0 +1,65 @@ +/* +** ============================================================================= +** Copyright (c) 2016 Texas Instruments Inc. +** +** This program is free software; you can redistribute it and/or modify it under +** the terms of the GNU General Public License as published by the Free Software +** Foundation; version 2. +** +** 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. +** +** File: +** tiload.h +** +** Description: +** header file for tiload.c +** +** ============================================================================= +*/ + +#ifndef _TILOAD_H +#define _TILOAD_H + +#ifdef CONFIG_COMPAT +#include +#endif + +#include "tas2557.h" + +#define BPR_REG(book, page, reg) (((book * 256 * 128) + \ + (page * 128)) + reg) + +/* typedefs required for the included header files */ +struct BPR { + unsigned char nBook; + unsigned char nPage; + unsigned char nRegister; +}; + +/* defines */ +#define DEVICE_NAME "tiload_node" + +#define TILOAD_IOC_MAGIC 0xE0 +#define TILOAD_IOMAGICNUM_GET _IOR(TILOAD_IOC_MAGIC, 1, int) +#define TILOAD_IOMAGICNUM_SET _IOW(TILOAD_IOC_MAGIC, 2, int) +#define TILOAD_BPR_READ _IOR(TILOAD_IOC_MAGIC, 3, struct BPR) +#define TILOAD_BPR_WRITE _IOW(TILOAD_IOC_MAGIC, 4, struct BPR) +#define TILOAD_IOCTL_SET_CHL _IOW(TILOAD_IOC_MAGIC, 5, int) +#define TILOAD_IOCTL_SET_CONFIG _IOW(TILOAD_IOC_MAGIC, 6, int) +#define TILOAD_IOCTL_SET_CALIBRATION _IOW(TILOAD_IOC_MAGIC, 7, int) + +#ifdef CONFIG_COMPAT +#define TILOAD_COMPAT_IOMAGICNUM_GET _IOR(TILOAD_IOC_MAGIC, 1, compat_int_t) +#define TILOAD_COMPAT_IOMAGICNUM_SET _IOW(TILOAD_IOC_MAGIC, 2, compat_int_t) +#define TILOAD_COMPAT_BPR_READ _IOR(TILOAD_IOC_MAGIC, 3, struct BPR) +#define TILOAD_COMPAT_BPR_WRITE _IOW(TILOAD_IOC_MAGIC, 4, struct BPR) +#define TILOAD_COMPAT_IOCTL_SET_CHL _IOW(TILOAD_IOC_MAGIC, 5, compat_int_t) +#define TILOAD_COMPAT_IOCTL_SET_CONFIG _IOW(TILOAD_IOC_MAGIC, 6, compat_int_t) +#define TILOAD_COMPAT_IOCTL_SET_CALIBRATION _IOW(TILOAD_IOC_MAGIC, 7, compat_int_t) +#endif + +int tiload_driver_init(struct tas2557_priv *pTAS2557); + +#endif diff --git a/techpack/audio/asoc/codecs/wcd-dsp-mgr.c b/techpack/audio/asoc/codecs/wcd-dsp-mgr.c index b45a9b3b7516..11c5931a1e0c 100644 --- a/techpack/audio/asoc/codecs/wcd-dsp-mgr.c +++ b/techpack/audio/asoc/codecs/wcd-dsp-mgr.c @@ -1203,6 +1203,9 @@ static int wdsp_mgr_parse_dt_entries(struct wdsp_mgr_priv *wdsp) return ret; } + wdsp->img_fname = "cpe_intl"; + pr_info("%s: using global wdsp fw: %s.\n", __func__, wdsp->img_fname); + ret = of_count_phandle_with_args(dev->of_node, "qcom,wdsp-components", NULL); diff --git a/techpack/audio/asoc/codecs/wcd-mbhc-adc.c b/techpack/audio/asoc/codecs/wcd-mbhc-adc.c index 96d1c8266764..cb4a79b9eab9 100644 --- a/techpack/audio/asoc/codecs/wcd-mbhc-adc.c +++ b/techpack/audio/asoc/codecs/wcd-mbhc-adc.c @@ -503,18 +503,15 @@ static bool wcd_is_special_headset(struct wcd_mbhc *mbhc) static void wcd_mbhc_adc_update_fsm_source(struct wcd_mbhc *mbhc, enum wcd_mbhc_plug_type plug_type) { - bool micbias2; - - micbias2 = mbhc->mbhc_cb->micbias_enable_status(mbhc, - MIC_BIAS_2); switch (plug_type) { case MBHC_PLUG_TYPE_HEADPHONE: WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); break; case MBHC_PLUG_TYPE_HEADSET: case MBHC_PLUG_TYPE_ANC_HEADPHONE: - if (!mbhc->is_hs_recording && !micbias2) - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 3); + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec, + MIC_BIAS_2, MICB_PULLUP_ENABLE); break; default: WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); diff --git a/techpack/audio/asoc/codecs/wcd-mbhc-v2.c b/techpack/audio/asoc/codecs/wcd-mbhc-v2.c index ffe573e33adb..e512a38a12ef 100644 --- a/techpack/audio/asoc/codecs/wcd-mbhc-v2.c +++ b/techpack/audio/asoc/codecs/wcd-mbhc-v2.c @@ -34,6 +34,8 @@ #include "wcd-mbhc-adc.h" #include "wcd-mbhc-v2-api.h" +#define CONFIG_AUDIO_UART_DEBUG + void wcd_mbhc_jack_report(struct wcd_mbhc *mbhc, struct snd_soc_jack *jack, int status, int mask) { @@ -214,7 +216,6 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, struct snd_soc_codec *codec = mbhc->codec; bool micbias2 = false; bool micbias1 = false; - u8 fsm_en = 0; pr_debug("%s: event %s (%d)\n", __func__, wcd_mbhc_get_event_string(event), event); @@ -255,12 +256,7 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, false); out_micb_en: /* Disable current source if micbias enabled */ - if (mbhc->mbhc_cb->mbhc_micbias_control) { - WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); - if (fsm_en) - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, - 0); - } else { + if (!mbhc->mbhc_cb->mbhc_micbias_control) { mbhc->is_hs_recording = true; wcd_enable_curr_micbias(mbhc, WCD_MBHC_EN_MB); } @@ -269,18 +265,6 @@ static int wcd_event_notify(struct notifier_block *self, unsigned long val, mbhc->mbhc_cb->set_cap_mode(codec, micbias1, true); break; case WCD_EVENT_PRE_MICBIAS_2_OFF: - /* - * Before MICBIAS_2 is turned off, if FSM is enabled, - * make sure current source is enabled so as to detect - * button press/release events - */ - if (mbhc->mbhc_cb->mbhc_micbias_control && - !mbhc->micbias_enable) { - WCD_MBHC_REG_READ(WCD_MBHC_FSM_EN, fsm_en); - if (fsm_en) - WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, - 3); - } break; /* MICBIAS usage change */ case WCD_EVENT_POST_DAPM_MICBIAS_2_OFF: @@ -845,6 +829,8 @@ void wcd_mbhc_find_plug_and_report(struct wcd_mbhc *mbhc, /* Disable HW FSM and current source */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec, + MIC_BIAS_2, MICB_PULLUP_DISABLE); /* Setup for insertion detection */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, 1); @@ -904,6 +890,8 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) bool micbias1 = false; struct snd_soc_codec *codec = mbhc->codec; enum snd_jack_types jack_type; + struct usbc_ana_audio_config *config = + &mbhc->mbhc_cfg->usbc_analog_cfg; dev_dbg(codec->dev, "%s: enter\n", __func__); WCD_MBHC_RSC_LOCK(mbhc); @@ -975,6 +963,8 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) /* Disable HW FSM */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_FSM_EN, 0); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_ISRC_CTL, 0); + mbhc->mbhc_cb->mbhc_micbias_control(mbhc->codec, + MIC_BIAS_2, MICB_PULLUP_DISABLE); if (mbhc->mbhc_cb->mbhc_common_micb_ctrl) mbhc->mbhc_cb->mbhc_common_micb_ctrl(codec, MBHC_COMMON_MICB_TAIL_CURR, false); @@ -1019,6 +1009,12 @@ static void wcd_mbhc_swch_irq_handler(struct wcd_mbhc *mbhc) WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_DETECTION_TYPE, 1); WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_ELECT_SCHMT_ISRC, 0); mbhc->extn_cable_hph_rem = false; + + if (config->usbc_en1_gpio_p) { + msm_cdc_pinctrl_select_sleep_state(config->usbc_en1_gpio_p); + pr_info("wcd_mbhc_swch_irq_handler: switch L/R to usb \n"); + } + wcd_mbhc_report_plug(mbhc, 0, jack_type); if (mbhc->mbhc_cfg->enable_usbc_analog) { @@ -1414,9 +1410,6 @@ static int wcd_mbhc_initialise(struct wcd_mbhc *mbhc) /* Button Debounce set to 16ms */ WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_BTN_DBNC, 2); - /* Enable micbias ramp */ - if (mbhc->mbhc_cb->mbhc_micb_ramp_control) - mbhc->mbhc_cb->mbhc_micb_ramp_control(codec, true); /* enable bias */ mbhc->mbhc_cb->mbhc_bias(codec, true); /* enable MBHC clock */ @@ -1576,6 +1569,181 @@ static int wcd_mbhc_set_keycode(struct wcd_mbhc *mbhc) return result; } +static int wcd_mbhc_usb_c_analog_setup_gpios(struct wcd_mbhc *mbhc, + bool active) +{ + int rc = 0; + struct usbc_ana_audio_config *config = + &mbhc->mbhc_cfg->usbc_analog_cfg; + + dev_dbg(mbhc->codec->dev, "%s: setting GPIOs active = %d\n", + __func__, active); + + if (active) { + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MIC_CLAMP_CTL, 2); + mbhc->mbhc_cfg->enable_dual_adc_gpio(mbhc->mbhc_cfg->dual_adc_gpio_node, 0); +#ifdef CONFIG_AUDIO_UART_DEBUG + msm_cdc_pinctrl_select_active_state(config->uart_audio_switch_gpio_p); + dev_dbg(mbhc->codec->dev, "disable uart\n"); +#endif + if (config->usbc_en1_gpio_p) + rc = msm_cdc_pinctrl_select_active_state( + config->usbc_en1_gpio_p); + if (rc == 0 && config->usbc_force_gpio_p) + rc = msm_cdc_pinctrl_select_active_state( + config->usbc_force_gpio_p); + mbhc->usbc_mode = POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER; + + //enable MBHC detect + if (mbhc->mbhc_cb->clk_setup) + mbhc->mbhc_cb->clk_setup(mbhc->codec, true); + /* insertion detected, enable L_DET_EN */ + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_L_DET_EN, 1); + } else { + /* no delay is required when disabling GPIOs */ + if (config->usbc_en1_gpio_p) + msm_cdc_pinctrl_select_sleep_state( + config->usbc_en1_gpio_p); + if (config->usbc_force_gpio_p) + msm_cdc_pinctrl_select_sleep_state( + config->usbc_force_gpio_p); +#ifdef CONFIG_AUDIO_UART_DEBUG + msm_cdc_pinctrl_select_sleep_state(config->uart_audio_switch_gpio_p); + dev_dbg(mbhc->codec->dev, "enable uart\n"); +#endif + mbhc->mbhc_cfg->enable_dual_adc_gpio(mbhc->mbhc_cfg->dual_adc_gpio_node, 1); + + mbhc->usbc_mode = POWER_SUPPLY_TYPEC_NONE; + WCD_MBHC_REG_UPDATE_BITS(WCD_MBHC_MIC_CLAMP_CTL, 0); + if (mbhc->mbhc_cfg->swap_gnd_mic) + mbhc->mbhc_cfg->swap_gnd_mic(mbhc->codec, false); + } + + return rc; +} + +/* workqueue */ +static void wcd_mbhc_usbc_analog_work_fn(struct work_struct *work) +{ + struct wcd_mbhc *mbhc = + container_of(work, struct wcd_mbhc, usbc_analog_work); + + wcd_mbhc_usb_c_analog_setup_gpios(mbhc, + mbhc->usbc_mode != POWER_SUPPLY_TYPEC_NONE); +} + +/* this callback function is used to process PMI notification */ +static int wcd_mbhc_usb_c_event_changed(struct notifier_block *nb, + unsigned long evt, void *ptr) +{ + int ret; + union power_supply_propval mode; + struct wcd_mbhc *mbhc = container_of(nb, struct wcd_mbhc, psy_nb); + struct snd_soc_codec *codec = mbhc->codec; + + if (ptr != mbhc->usb_psy || evt != PSY_EVENT_PROP_CHANGED) + return 0; + + ret = power_supply_get_property(mbhc->usb_psy, + POWER_SUPPLY_PROP_TYPEC_MODE, &mode); + if (ret) { + dev_err(codec->dev, "%s: Unable to read USB TYPEC_MODE: %d\n", + __func__, ret); + return ret; + } + + dev_dbg(codec->dev, "%s: USB change event received\n", + __func__); + dev_dbg(codec->dev, "%s: supply mode %d, expected %d\n", __func__, + mode.intval, POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER); + + switch (mode.intval) { + case POWER_SUPPLY_TYPEC_SINK_AUDIO_ADAPTER: + case POWER_SUPPLY_TYPEC_NONE: + dev_dbg(codec->dev, "%s: usbc_mode: %d; mode.intval: %d\n", + __func__, mbhc->usbc_mode, mode.intval); + + if (mbhc->usbc_mode == mode.intval) + break; /* filter notifications received before */ + mbhc->usbc_mode = mode.intval; + + dev_dbg(codec->dev, "%s: queueing usbc_analog_work\n", + __func__); + schedule_work(&mbhc->usbc_analog_work); + break; + default: + break; + } + return ret; +} + +/* PMI registration code */ +static int wcd_mbhc_usb_c_analog_init(struct wcd_mbhc *mbhc) +{ + int ret = 0; + struct snd_soc_codec *codec = mbhc->codec; + + dev_dbg(mbhc->codec->dev, "%s: usb-c analog setup start\n", __func__); + INIT_WORK(&mbhc->usbc_analog_work, wcd_mbhc_usbc_analog_work_fn); + + mbhc->usb_psy = power_supply_get_by_name("usb"); + if (IS_ERR_OR_NULL(mbhc->usb_psy)) { + dev_err(codec->dev, "%s: could not get USB psy info\n", + __func__); + ret = -EPROBE_DEFER; + if (IS_ERR(mbhc->usb_psy)) + ret = PTR_ERR(mbhc->usb_psy); + mbhc->usb_psy = NULL; + goto err; + } + + ret = wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); + if (ret) { + dev_err(codec->dev, "%s: error while setting USBC ana gpios\n", + __func__); + goto err; + } + +err: + return ret; +} + +static int wcd_mbhc_usb_c_analog_deinit(struct wcd_mbhc *mbhc) +{ + wcd_mbhc_usb_c_analog_setup_gpios(mbhc, false); + + /* deregister from PMI */ + power_supply_unreg_notifier(&mbhc->psy_nb); + + return 0; +} + +static int wcd_mbhc_init_gpio(struct wcd_mbhc *mbhc, + struct wcd_mbhc_config *mbhc_cfg, + const char *gpio_dt_str, + int *gpio, struct device_node **gpio_dn) +{ + int rc = 0; + struct snd_soc_codec *codec = mbhc->codec; + struct snd_soc_card *card = codec->component.card; + + dev_dbg(mbhc->codec->dev, "%s: gpio %s\n", __func__, gpio_dt_str); + + *gpio_dn = of_parse_phandle(card->dev->of_node, gpio_dt_str, 0); + + if (!(*gpio_dn)) { + *gpio = of_get_named_gpio(card->dev->of_node, gpio_dt_str, 0); + if (!gpio_is_valid(*gpio)) { + dev_err(card->dev, "%s, property %s not in node %s", + __func__, gpio_dt_str, + card->dev->of_node->full_name); + rc = -EINVAL; + } + } + + return rc; +} + static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, unsigned long mode, void *ptr) { @@ -1598,13 +1766,16 @@ static int wcd_mbhc_usbc_ana_event_handler(struct notifier_block *nb, int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) { int rc = 0; + struct usbc_ana_audio_config *config; struct snd_soc_codec *codec; struct snd_soc_card *card; const char *usb_c_dt = "qcom,msm-mbhc-usbc-audio-supported"; + const char *fsa4476_dt = "qcom,fsa4476-gpio-support"; if (!mbhc || !mbhc_cfg) return -EINVAL; + config = &mbhc_cfg->usbc_analog_cfg; codec = mbhc->codec; card = codec->component.card; @@ -1632,13 +1803,60 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) dev_dbg(mbhc->codec->dev, "%s: usbc analog enabled\n", __func__); mbhc->swap_thr = GND_MIC_USBC_SWAP_THRESHOLD; - mbhc->fsa_np = of_parse_phandle(card->dev->of_node, - "fsa4480-i2c-handle", 0); - if (!mbhc->fsa_np) { - dev_err(card->dev, "%s: fsa4480 i2c node not found\n", + + mbhc_cfg->use_fsa4476_gpio = 0; + if (of_find_property(card->dev->of_node, fsa4476_dt, NULL)) { + rc = of_property_read_u32(card->dev->of_node, fsa4476_dt, + &mbhc_cfg->use_fsa4476_gpio); + if (rc != 0) { + dev_dbg(card->dev, + "%s: %s in dt node is missing or false\n", + __func__, fsa4476_dt); + } + } + + if (mbhc_cfg->use_fsa4476_gpio != 0) { + rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, + "qcom,usbc-analog-en1-gpio", + &config->usbc_en1_gpio, + &config->usbc_en1_gpio_p); + if (rc) + goto err; + + dev_dbg(mbhc->codec->dev, "%s: calling usb_c_analog_init\n", __func__); - rc = -EINVAL; - goto err; + +#ifdef CONFIG_AUDIO_UART_DEBUG + if (of_find_property(card->dev->of_node, + "qcom,uart-audio-sw-gpio", + NULL)) { + rc = wcd_mbhc_init_gpio(mbhc, mbhc_cfg, + "qcom,uart-audio-sw-gpio", + &config->uart_audio_switch_gpio, + &config->uart_audio_switch_gpio_p); + if (rc) + goto err; + } +#endif + + rc = wcd_mbhc_usb_c_analog_init(mbhc); + if (rc) { + rc = EPROBE_DEFER; + goto err; + } + dev_dbg(card->dev, "%s: Using fsa4476 analog gpio switch\n", __func__); + } else { + mbhc->fsa_np = of_parse_phandle(card->dev->of_node, + "fsa4480-i2c-handle", 0); + if (!mbhc->fsa_np) { + dev_err(card->dev, "%s: fsa4480 i2c node not found\n", + __func__); + rc = -EINVAL; + goto err; + } else { + dev_dbg(card->dev, + "%s: Using USB fsa4480 i2c switch\n", __func__); + } } } @@ -1665,13 +1883,44 @@ int wcd_mbhc_start(struct wcd_mbhc *mbhc, struct wcd_mbhc_config *mbhc_cfg) } if (mbhc_cfg->enable_usbc_analog) { - mbhc->fsa_nb.notifier_call = wcd_mbhc_usbc_ana_event_handler; - mbhc->fsa_nb.priority = 0; - rc = fsa4480_reg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); + if (mbhc_cfg->use_fsa4476_gpio == 0) { + mbhc->fsa_nb.notifier_call = wcd_mbhc_usbc_ana_event_handler; + mbhc->fsa_nb.priority = 0; + rc = fsa4480_reg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); + } else { + mbhc->psy_nb.notifier_call = wcd_mbhc_usb_c_event_changed; + mbhc->psy_nb.priority = 0; + rc = power_supply_reg_notifier(&mbhc->psy_nb); + if (rc) { + dev_err(codec->dev, "%s: power supply registration failed\n", + __func__); + goto err; + } + + /* + * as part of the init sequence check if there is a connected + * USB C analog adapter + */ + dev_dbg(mbhc->codec->dev, "%s: verify if USB adapter is already inserted\n", + __func__); + rc = wcd_mbhc_usb_c_event_changed(&mbhc->psy_nb, + PSY_EVENT_PROP_CHANGED, + mbhc->usb_psy); + } } return rc; err: + if (config->usbc_en1_gpio > 0) { + dev_dbg(card->dev, "%s free usb en1 gpio %d\n", + __func__, config->usbc_en1_gpio); + gpio_free(config->usbc_en1_gpio); + config->usbc_en1_gpio = 0; + } + if (config->usbc_en1_gpio_p) + of_node_put(config->usbc_en1_gpio_p); + if (config->usbc_force_gpio_p) + of_node_put(config->usbc_force_gpio_p); dev_dbg(mbhc->codec->dev, "%s: leave %d\n", __func__, rc); return rc; } @@ -1679,6 +1928,8 @@ EXPORT_SYMBOL(wcd_mbhc_start); void wcd_mbhc_stop(struct wcd_mbhc *mbhc) { + struct usbc_ana_audio_config *config = &mbhc->mbhc_cfg->usbc_analog_cfg; + pr_debug("%s: enter\n", __func__); if (mbhc->current_plug != MBHC_PLUG_TYPE_NONE) { @@ -1703,8 +1954,20 @@ void wcd_mbhc_stop(struct wcd_mbhc *mbhc) mbhc->mbhc_cal = NULL; } - if (mbhc->mbhc_cfg->enable_usbc_analog) - fsa4480_unreg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); + if (mbhc->mbhc_cfg->enable_usbc_analog) { + if (mbhc->mbhc_cfg->use_fsa4476_gpio == 0) { + fsa4480_unreg_notifier(&mbhc->fsa_nb, mbhc->fsa_np); + } + + wcd_mbhc_usb_c_analog_deinit(mbhc); + + /* free GPIOs */ + if (config->usbc_en1_gpio > 0) + gpio_free(config->usbc_en1_gpio); + + if (config->usbc_en1_gpio_p) + of_node_put(config->usbc_en1_gpio_p); + } pr_debug("%s: leave\n", __func__); } diff --git a/techpack/audio/asoc/codecs/wcd-mbhc-v2.h b/techpack/audio/asoc/codecs/wcd-mbhc-v2.h index a20765f56691..f6dc1fec2265 100644 --- a/techpack/audio/asoc/codecs/wcd-mbhc-v2.h +++ b/techpack/audio/asoc/codecs/wcd-mbhc-v2.h @@ -423,6 +423,21 @@ enum mbhc_moisture_rref { R_184_KOHM, }; +struct usbc_ana_audio_config { + int usbc_en1_gpio; + int usbc_en2_gpio; + int usbc_force_gpio; + int euro_us_hw_switch_gpio; + int uart_audio_switch_gpio; + int subpcb_id_gpio; + struct device_node *usbc_en1_gpio_p; /* used by pinctrl API */ + struct device_node *usbc_en2_gpio_p; /* used by pinctrl API */ + struct device_node *usbc_force_gpio_p; /* used by pinctrl API */ + struct device_node *euro_us_hw_switch_gpio_p; /* used by pinctrl API */ + struct device_node *uart_audio_switch_gpio_p; /* used by pinctrl API */ + struct device_node *subpcb_id_gpio_p; /* used by pinctrl API */ +}; + struct wcd_mbhc_config { bool read_fw_bin; void *calibration; @@ -438,7 +453,11 @@ struct wcd_mbhc_config { int anc_micbias; bool enable_anc_mic_detect; u32 enable_usbc_analog; + struct usbc_ana_audio_config usbc_analog_cfg; + u32 use_fsa4476_gpio; bool moisture_duty_cycle_en; + void (*enable_dual_adc_gpio)(struct device_node *node, bool en); + struct device_node *dual_adc_gpio_node; }; struct wcd_mbhc_intr { @@ -598,6 +617,12 @@ struct wcd_mbhc { unsigned long intr_status; bool is_hph_ocp_pending; + bool usbc_force_pr_mode; + int usbc_mode; + struct notifier_block psy_nb; + struct power_supply *usb_psy; + struct work_struct usbc_analog_work; + struct wcd_mbhc_fn *mbhc_fn; bool force_linein; struct device_node *fsa_np; diff --git a/techpack/audio/asoc/codecs/wcd9335.c b/techpack/audio/asoc/codecs/wcd9335.c index 4706a0e08343..04efbb544bf9 100644 --- a/techpack/audio/asoc/codecs/wcd9335.c +++ b/techpack/audio/asoc/codecs/wcd9335.c @@ -7820,6 +7820,12 @@ static int tasha_mad_input_put(struct snd_kcontrol *kcontrol, "%s: tasha input widget = %s\n", __func__, mad_input_widget); + if (!strcmp("AMIC2", mad_input_widget)) { + mic_bias_found = 2; + dev_info(codec->dev, + "%s: tavil input widget = %s, enable MIC BIAS2 directly.\n", + __func__, mad_input_widget); + } else { for (i = 0; i < card->num_of_dapm_routes; i++) { if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) { source_widget = card->of_dapm_routes[i].source; @@ -7849,6 +7855,7 @@ static int tasha_mad_input_put(struct snd_kcontrol *kcontrol, } } } + } if (!mic_bias_found) { dev_err(codec->dev, diff --git a/techpack/audio/asoc/codecs/wcd934x/Android.mk b/techpack/audio/asoc/codecs/wcd934x/Android.mk deleted file mode 100644 index ada428675e78..000000000000 --- a/techpack/audio/asoc/codecs/wcd934x/Android.mk +++ /dev/null @@ -1,62 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,sdm845),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m -endif - -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile atoll $(MSMSTEPPE) $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=wcd934x_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd934x.ko -LOCAL_MODULE_KBUILD_NAME := wcd934x_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/wcd934x/Kbuild b/techpack/audio/asoc/codecs/wcd934x/Kbuild index 34e7d62017df..444765851c1f 100644 --- a/techpack/audio/asoc/codecs/wcd934x/Kbuild +++ b/techpack/audio/asoc/codecs/wcd934x/Kbuild @@ -135,6 +135,3 @@ endif # Module information used by KBuild framework obj-$(CONFIG_SND_SOC_WCD934X) += wcd934x_dlkm.o wcd934x_dlkm-y := $(WCD934X_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c b/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c index 3aa8fe7aea1c..e411aac3441c 100644 --- a/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c +++ b/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.c @@ -987,6 +987,28 @@ int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, } EXPORT_SYMBOL(tavil_mbhc_get_impedance); + +int tavil_mb_pull_down(struct snd_soc_codec *codec, bool active, + int value) +{ + int oldv = 0; + + if (active) { + oldv = snd_soc_read(codec, WCD934X_ANA_MICB2); + snd_soc_update_bits(codec, WCD934X_ANA_MBHC_ELECT, + 0x80, 0x00); + snd_soc_update_bits(codec, WCD934X_ANA_MICB2, 0xC0, 0xC0); + } else { + snd_soc_write(codec, WCD934X_ANA_MICB2, value); + snd_soc_update_bits(codec, WCD934X_ANA_MBHC_ELECT, + 0x80, 0x80); + } + + return oldv; +} +EXPORT_SYMBOL(tavil_mb_pull_down); + + /* * tavil_mbhc_hs_detect: starts mbhc insertion/removal functionality * @codec: handle to snd_soc_codec * diff --git a/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.h b/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.h index 53c886da0f6b..7995017f2e0d 100644 --- a/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.h +++ b/techpack/audio/asoc/codecs/wcd934x/wcd934x-mbhc.h @@ -47,6 +47,10 @@ extern int tavil_mbhc_post_ssr_init(struct wcd934x_mbhc *mbhc, struct snd_soc_codec *codec); extern int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, uint32_t *zl, uint32_t *zr); + +extern int tavil_mb_pull_down(struct snd_soc_codec *codec, bool active, + int value); + #else static inline int tavil_mbhc_init(struct wcd934x_mbhc **mbhc, struct snd_soc_codec *codec, @@ -79,6 +83,14 @@ static inline int tavil_mbhc_get_impedance(struct wcd934x_mbhc *wcd934x_mbhc, *zr = 0; return -EINVAL; } + + +static inline int tavil_mb_pull_down(struct snd_soc_codec *codec, bool active, + int value) +{ + return 0; +} + #endif #endif /* __WCD934X_MBHC_H__ */ diff --git a/techpack/audio/asoc/codecs/wcd934x/wcd934x.c b/techpack/audio/asoc/codecs/wcd934x/wcd934x.c index 300ffbc68d42..a4c6f30322ac 100644 --- a/techpack/audio/asoc/codecs/wcd934x/wcd934x.c +++ b/techpack/audio/asoc/codecs/wcd934x/wcd934x.c @@ -644,6 +644,7 @@ struct tavil_priv { struct platform_device *pdev_child_devices [WCD934X_CHILD_DEVICES_MAX]; int child_count; + int micbias_num; struct regulator *micb_load; int micb_load_low; int micb_load_high; @@ -5674,10 +5675,25 @@ static int tavil_compander_put(struct snd_kcontrol *kcontrol, /* Set Gain Source Select based on compander enable/disable */ snd_soc_update_bits(codec, WCD934X_HPH_L_EN, 0x20, (value ? 0x00:0x20)); + /* Disable Compander Clock */ + snd_soc_update_bits(codec, WCD934X_CDC_RX1_RX_PATH_CFG0, 0x02, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER1_CTL0, 0x04, 0x04); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER1_CTL0, 0x02, 0x02); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER1_CTL0, 0x02, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER1_CTL0, 0x01, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER1_CTL0, 0x04, 0x00); break; case COMPANDER_2: snd_soc_update_bits(codec, WCD934X_HPH_R_EN, 0x20, (value ? 0x00:0x20)); + /* Disable Compander Clock */ + snd_soc_update_bits(codec, WCD934X_CDC_RX2_RX_PATH_CFG0, 0x02, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER2_CTL0, 0x04, 0x04); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER2_CTL0, 0x02, 0x02); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER2_CTL0, 0x02, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER2_CTL0, 0x01, 0x00); + snd_soc_update_bits(codec, WCD934X_CDC_COMPANDER2_CTL0, 0x04, 0x00); + break; case COMPANDER_3: case COMPANDER_4: @@ -5972,32 +5988,39 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol, "%s: tavil input widget = %s, adc_input = %s\n", __func__, mad_input_widget, is_adc_input ? "true" : "false"); - for (i = 0; i < card->num_of_dapm_routes; i++) { - if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) { - source_widget = card->of_dapm_routes[i].source; - if (!source_widget) { - dev_err(codec->dev, - "%s: invalid source widget\n", - __func__); - return -EINVAL; - } + if (!strcmp("AMIC2", mad_input_widget)) { + mic_bias_found = 2; + dev_info(codec->dev, + "%s: tavil input widget = %s, enable MIC BIAS2 directly.\n", + __func__, mad_input_widget); + } else { + for (i = 0; i < card->num_of_dapm_routes; i++) { + if (!strcmp(card->of_dapm_routes[i].sink, mad_input_widget)) { + source_widget = card->of_dapm_routes[i].source; + if (!source_widget) { + dev_err(codec->dev, + "%s: invalid source widget\n", + __func__); + return -EINVAL; + } - if (strnstr(source_widget, - "MIC BIAS1", sizeof("MIC BIAS1"))) { - mic_bias_found = 1; - break; - } else if (strnstr(source_widget, - "MIC BIAS2", sizeof("MIC BIAS2"))) { - mic_bias_found = 2; - break; - } else if (strnstr(source_widget, - "MIC BIAS3", sizeof("MIC BIAS3"))) { - mic_bias_found = 3; - break; - } else if (strnstr(source_widget, - "MIC BIAS4", sizeof("MIC BIAS4"))) { - mic_bias_found = 4; - break; + if (strnstr(source_widget, + "MIC BIAS1", sizeof("MIC BIAS1"))) { + mic_bias_found = 1; + break; + } else if (strnstr(source_widget, + "MIC BIAS2", sizeof("MIC BIAS2"))) { + mic_bias_found = 2; + break; + } else if (strnstr(source_widget, + "MIC BIAS3", sizeof("MIC BIAS3"))) { + mic_bias_found = 3; + break; + } else if (strnstr(source_widget, + "MIC BIAS4", sizeof("MIC BIAS4"))) { + mic_bias_found = 4; + break; + } } } } @@ -6025,6 +6048,62 @@ static int tavil_mad_input_put(struct snd_kcontrol *kcontrol, return 0; } +static const char *const tavil_micbias_text[] = { + "OFF", "MICBIAS1", "MICBIAS2", "MICBIAS3", "MICBIAS4" +}; + +static const struct soc_enum tavil_micbias_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(tavil_micbias_text), + tavil_micbias_text); + +static int tavil_micb_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec); + + ucontrol->value.integer.value[0] = priv->micbias_num;; + + dev_dbg(codec->dev, "%s: tavil_micbias_num = %s\n", __func__, + tavil_micbias_text[priv->micbias_num]); + + return 0; +} + +static int tavil_micb_status_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); + struct tavil_priv *priv = snd_soc_codec_get_drvdata(codec); + u8 tavil_micbias_num; + + tavil_micbias_num = ucontrol->value.integer.value[0]; + + if (tavil_micbias_num >= sizeof(tavil_micbias_text)/ + sizeof(tavil_micbias_text[0])) { + dev_err(codec->dev, + "%s: tavil_micbias_num = %d out of bounds\n", + __func__, tavil_micbias_num); + return -EINVAL; + } + priv->micbias_num = tavil_micbias_num; + + if (tavil_micbias_num == 0) { + tavil_codec_enable_standalone_micbias(codec, 1, false); + tavil_codec_enable_standalone_micbias(codec, 2, false); + tavil_codec_enable_standalone_micbias(codec, 3, false); + tavil_codec_enable_standalone_micbias(codec, 4, false); + dev_err(codec->dev, "====>PFT: %s: turn off all micbias.\n", __func__); + } else { + tavil_codec_enable_standalone_micbias(codec, tavil_micbias_num, true); + dev_err(codec->dev, "====>PFT: %s: turn on micbias %d.\n", + __func__, tavil_micbias_num); + } + + return 0; +} + + static int tavil_ear_pa_gain_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { @@ -6328,8 +6407,8 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = { SOC_ENUM_EXT("SPKR Right Boost Max State", tavil_spkr_boost_stage_enum, tavil_spkr_right_boost_stage_get, tavil_spkr_right_boost_stage_put), - SOC_SINGLE_TLV("HPHL Volume", WCD934X_HPH_L_EN, 0, 20, 1, line_gain), - SOC_SINGLE_TLV("HPHR Volume", WCD934X_HPH_R_EN, 0, 20, 1, line_gain), + SOC_SINGLE_TLV("HPHL Volume", WCD934X_HPH_L_EN, 0, 24, 1, line_gain), + SOC_SINGLE_TLV("HPHR Volume", WCD934X_HPH_R_EN, 0, 24, 1, line_gain), SOC_SINGLE_TLV("LINEOUT1 Volume", WCD934X_DIFF_LO_LO1_COMPANDER, 3, 16, 1, line_gain), SOC_SINGLE_TLV("LINEOUT2 Volume", WCD934X_DIFF_LO_LO2_COMPANDER, @@ -6524,6 +6603,10 @@ static const struct snd_kcontrol_new tavil_snd_controls[] = { SOC_ENUM_EXT("MAD Input", tavil_conn_mad_enum, tavil_mad_input_get, tavil_mad_input_put), + SOC_ENUM_EXT("Mic Bias", tavil_micbias_enum, + tavil_micb_status_get, tavil_micb_status_put), + + SOC_SINGLE_EXT("DMIC1_CLK_PIN_MODE", SND_SOC_NOPM, 17, 1, 0, tavil_dmic_pin_mode_get, tavil_dmic_pin_mode_put), @@ -11145,6 +11228,7 @@ static int tavil_probe(struct platform_device *pdev) tavil->swr.plat_data.clk = tavil_swrm_clock; tavil->swr.plat_data.handle_irq = tavil_swrm_handle_irq; tavil->swr.spkr_gain_offset = WCD934X_RX_GAIN_OFFSET_0_DB; + tavil->micbias_num = 0; /* Register for Clock */ wcd_ext_clk = clk_get(tavil->wcd9xxx->dev, "wcd_clk"); diff --git a/techpack/audio/asoc/codecs/wcd9360/Android.mk b/techpack/audio/asoc/codecs/wcd9360/Android.mk deleted file mode 100644 index 492061265f26..000000000000 --- a/techpack/audio/asoc/codecs/wcd9360/Android.mk +++ /dev/null @@ -1,50 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msmnile),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=wcd9360_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd9360.ko -LOCAL_MODULE_KBUILD_NAME := wcd9360_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/wcd9360/Kbuild b/techpack/audio/asoc/codecs/wcd9360/Kbuild index 8753c005bee0..e85cb95278c4 100644 --- a/techpack/audio/asoc/codecs/wcd9360/Kbuild +++ b/techpack/audio/asoc/codecs/wcd9360/Kbuild @@ -109,6 +109,3 @@ endif # Module information used by KBuild framework obj-$(CONFIG_SND_SOC_WCD9360) += wcd9360_dlkm.o wcd9360_dlkm-y := $(WCD9360_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/wcd937x/Android.mk b/techpack/audio/asoc/codecs/wcd937x/Android.mk deleted file mode 100644 index dec151ad0438..000000000000 --- a/techpack/audio/asoc/codecs/wcd937x/Android.mk +++ /dev/null @@ -1,57 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile atoll $(MSMSTEPPE) $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=wcd937x_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd937x.ko -LOCAL_MODULE_KBUILD_NAME := wcd937x_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wcd937x_slave.ko -LOCAL_MODULE_KBUILD_NAME := wcd937x_slave_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/asoc/codecs/wcd937x/Kbuild b/techpack/audio/asoc/codecs/wcd937x/Kbuild index bfc6f4fd5e6e..debddcea72d5 100644 --- a/techpack/audio/asoc/codecs/wcd937x/Kbuild +++ b/techpack/audio/asoc/codecs/wcd937x/Kbuild @@ -117,6 +117,3 @@ wcd937x_dlkm-y := $(WCD937X_OBJS) obj-$(CONFIG_SND_SOC_WCD937X_SLAVE) += wcd937x_slave_dlkm.o wcd937x_slave_dlkm-y := $(WCD937X_SLAVE_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/asoc/codecs/wcd9xxx-common-v2.c b/techpack/audio/asoc/codecs/wcd9xxx-common-v2.c index 478c0c6d72e6..934519c9adee 100644 --- a/techpack/audio/asoc/codecs/wcd9xxx-common-v2.c +++ b/techpack/audio/asoc/codecs/wcd9xxx-common-v2.c @@ -794,6 +794,7 @@ static void wcd_clsh_state_hph_ear(struct snd_soc_codec *codec, wcd_clsh_set_gain_path(codec, mode); wcd_clsh_set_flyback_mode(codec, mode); wcd_clsh_set_buck_mode(codec, mode); + wcd_clsh_set_hph_mode(codec, mode); } } else { if (req_state == WCD_CLSH_STATE_EAR) { diff --git a/techpack/audio/asoc/msm-compress-q6-v2.c b/techpack/audio/asoc/msm-compress-q6-v2.c index 26731e180d20..bd38c7329bba 100644 --- a/techpack/audio/asoc/msm-compress-q6-v2.c +++ b/techpack/audio/asoc/msm-compress-q6-v2.c @@ -1291,7 +1291,7 @@ static int msm_compr_configure_dsp_for_playback struct snd_compr_runtime *runtime = cstream->runtime; struct msm_compr_audio *prtd = runtime->private_data; struct snd_soc_pcm_runtime *soc_prtd = cstream->private_data; - uint16_t bits_per_sample = 16; + uint16_t bits_per_sample = 24; int dir = IN, ret = 0; struct audio_client *ac = prtd->audio_client; uint32_t stream_index; @@ -2253,7 +2253,7 @@ static int msm_compr_trigger(struct snd_compr_stream *cstream, int cmd) unsigned long flags; int stream_id; uint32_t stream_index; - uint16_t bits_per_sample = 16; + uint16_t bits_per_sample = 24; spin_lock_irqsave(&prtd->lock, flags); if (atomic_read(&prtd->error)) { diff --git a/techpack/audio/asoc/msm-pcm-routing-v2.c b/techpack/audio/asoc/msm-pcm-routing-v2.c index ce670a241bcc..87cf29ac70e0 100644 --- a/techpack/audio/asoc/msm-pcm-routing-v2.c +++ b/techpack/audio/asoc/msm-pcm-routing-v2.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include "msm-pcm-routing-v2.h" #include "msm-pcm-routing-devdep.h" @@ -46,6 +48,10 @@ #include "msm-dolby-dap-config.h" #include "msm-ds2-dap-config.h" +#ifdef CONFIG_MSM_CSPL +#include +#endif + #ifndef CONFIG_DOLBY_DAP #undef DOLBY_ADM_COPP_TOPOLOGY_ID #define DOLBY_ADM_COPP_TOPOLOGY_ID 0xFFFFFFFE @@ -80,6 +86,8 @@ static int msm_ec_ref_bit_format = SNDRV_PCM_FORMAT_S16_LE; static int msm_ec_ref_sampling_rate = 48000; static uint32_t voc_session_id = ALL_SESSION_VSID; static int msm_route_ext_ec_ref; +static int wakeup_ext_ec_ref = 0; +static int voip_ext_ec_common_ref = 0; static bool is_custom_stereo_on; static bool is_ds2_on; static bool swap_ch; @@ -3822,9 +3830,16 @@ static const struct snd_kcontrol_new ec_ref_param_controls[] = { static int msm_routing_ec_ref_rx_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) { - pr_debug("%s: ec_ref_rx = %d", __func__, msm_route_ec_ref_rx); + struct snd_soc_dapm_widget *widget = + snd_soc_dapm_kcontrol_widget(kcontrol); + + pr_debug("%s: wakeup_ext_ec_ref = %d, voip_ext_ec_common_ref = %d", + __func__, wakeup_ext_ec_ref, voip_ext_ec_common_ref); mutex_lock(&routing_lock); - ucontrol->value.integer.value[0] = msm_route_ec_ref_rx; + if (!strncmp(widget->name, "AUDIO_REF_EC_UL10 MUX", strlen("AUDIO_REF_EC_UL10 MUX"))) + ucontrol->value.integer.value[0] = voip_ext_ec_common_ref; + else + ucontrol->value.integer.value[0] = wakeup_ext_ec_ref; mutex_unlock(&routing_lock); return 0; } @@ -3837,6 +3852,7 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, snd_soc_dapm_kcontrol_widget(kcontrol); struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; struct snd_soc_dapm_update *update = NULL; + bool state = true; mutex_lock(&routing_lock); @@ -3844,6 +3860,7 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, case 0: msm_route_ec_ref_rx = 0; ec_ref_port_id = AFE_PORT_INVALID; + state = false; break; case 1: msm_route_ec_ref_rx = 1; @@ -3990,14 +4007,29 @@ static int msm_routing_ec_ref_rx_put(struct snd_kcontrol *kcontrol, pr_err("%s EC ref rx %ld not valid\n", __func__, ucontrol->value.integer.value[0]); ec_ref_port_id = AFE_PORT_INVALID; + state = false; break; } - adm_ec_ref_rx_id(ec_ref_port_id); + pr_debug("%s: msm_route_ec_ref_rx = %d\n", __func__, msm_route_ec_ref_rx); - mutex_unlock(&routing_lock); - snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, + + if (!strncmp(widget->name, "AUDIO_REF_EC_UL10 MUX", strlen("AUDIO_REF_EC_UL10 MUX"))) + voip_ext_ec_common_ref = msm_route_ec_ref_rx; + else + wakeup_ext_ec_ref = msm_route_ec_ref_rx; + pr_debug("%s: state %d, wakeup_ext_ec_ref %d, voip_ext_ec_common_ref %d\n", __func__, + state, wakeup_ext_ec_ref, voip_ext_ec_common_ref); + + if (state || (!state && wakeup_ext_ec_ref == 0 && voip_ext_ec_common_ref == 0)) { + pr_info("%s: update state!\n", __func__); + adm_ec_ref_rx_id(ec_ref_port_id); + mutex_unlock(&routing_lock); + snd_soc_dapm_mux_update_power(widget->dapm, kcontrol, msm_route_ec_ref_rx, e, update); + } else { + mutex_unlock(&routing_lock); + } return 0; } @@ -23895,6 +23927,8 @@ static int msm_routing_probe(struct snd_soc_platform *platform) port_multi_channel_map_mixer_controls, ARRAY_SIZE(port_multi_channel_map_mixer_controls)); + elliptic_add_platform_controls(platform); + return 0; } diff --git a/techpack/audio/asoc/sm8150.c b/techpack/audio/asoc/sm8150.c index 71d1204c4369..a4fe10002f39 100644 --- a/techpack/audio/asoc/sm8150.c +++ b/techpack/audio/asoc/sm8150.c @@ -39,6 +39,7 @@ #include "codecs/wcd9360/wcd9360.h" #include "codecs/wsa881x.h" #include "codecs/wcd-mbhc-v2.h" +#include #define DRV_NAME "sm8150-asoc-snd" @@ -68,6 +69,8 @@ #define WCN_CDC_SLIM_RX_CH_MAX 2 #define WCN_CDC_SLIM_TX_CH_MAX 3 +#define CS35L41_CODEC_NAME "cs35l41.0-0040" + #define ADSP_STATE_READY_TIMEOUT_MS 3000 #define MSM_LL_QOS_VALUE 300 /* time in us to ensure LPM doesn't go in C3/C4 */ #define MSM_HIFI_ON 1 @@ -170,10 +173,13 @@ struct msm_pinctrl_info { struct msm_asoc_mach_data { struct snd_info_entry *codec_root; struct msm_pinctrl_info pinctrl_info; + int usbc_en2_gpio; /* used by gpio driver API */ struct device_node *us_euro_gpio_p; /* used by pinctrl API */ + struct pinctrl *usbc_en2_gpio_p; /* used by pinctrl API */ struct device_node *hph_en1_gpio_p; /* used by pinctrl API */ struct device_node *hph_en0_gpio_p; /* used by pinctrl API */ struct device_node *fsa_handle; + struct device_node *adc2_sel_gpio_p; /* used by pinctrl API */ struct snd_soc_codec *codec; struct work_struct adsp_power_up_work; }; @@ -635,9 +641,9 @@ static struct wcd_mbhc_config wcd_mbhc_cfg = { .swap_gnd_mic = NULL, .hs_ext_micbias = true, .key_code[0] = KEY_MEDIA, - .key_code[1] = KEY_VOICECOMMAND, - .key_code[2] = KEY_VOLUMEUP, - .key_code[3] = KEY_VOLUMEDOWN, + .key_code[1] = BTN_1, + .key_code[2] = BTN_2, + .key_code[3] = 0, .key_code[4] = 0, .key_code[5] = 0, .key_code[6] = 0, @@ -2949,6 +2955,32 @@ static int msm_hifi_put(struct snd_kcontrol *kcontrol, return 0; } +static int usbhs_direction_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = NULL; + struct snd_soc_card *card = NULL; + struct msm_asoc_mach_data *pdata = NULL; + + ucontrol->value.integer.value[0] = 0; + + codec = snd_soc_kcontrol_codec(kcontrol); + if (codec) { + card = codec->component.card; + if (card) { + pdata = snd_soc_card_get_drvdata(card); + if (pdata){ + if (pdata->usbc_en2_gpio_p) { + ucontrol->value.integer.value[0] = gpio_get_value_cansleep(pdata->usbc_en2_gpio); + } else if (pdata->usbc_en2_gpio > 0) { + ucontrol->value.integer.value[0] = gpio_get_value_cansleep(pdata->usbc_en2_gpio); + } + } + } + } + return 0; +} + static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_ENUM_EXT("SLIM_0_RX Channels", slim_0_rx_chs, slim_rx_ch_get, slim_rx_ch_put), @@ -3238,6 +3270,8 @@ static const struct snd_kcontrol_new msm_snd_controls[] = { SOC_SINGLE_MULTI_EXT("TDM Slot Map", SND_SOC_NOPM, 0, 255, 0, 4, NULL, tdm_slot_map_put), + SOC_SINGLE_EXT("USB Headset Direction", 0, 0, UINT_MAX, 0, + usbhs_direction_get, NULL), }; static int msm_snd_enable_codec_ext_clk(struct snd_soc_codec *codec, @@ -3341,6 +3375,62 @@ static int msm_hifi_ctrl_event(struct snd_soc_dapm_widget *w, return 0; } +/* +static int external_amic2_sel_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = amic2_sel_state; + return 0; +} +*/ + +static void external_enable_dual_adc_gpio(struct device_node *np, bool val) +{ + if (!np) { + pr_err("%s: device node is NULL!", __func__); + return; + } + + if (val == 1) { + msm_cdc_pinctrl_select_active_state(np); + pr_info("%s: enable Dual ADC \n", __func__); + } else { + msm_cdc_pinctrl_select_sleep_state(np); + pr_info("%s: disable Dual ADC \n", __func__); + } +} + +static int external_amic2_sel_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol); + struct snd_soc_card *card = dapm->card; + struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); + unsigned int val; + + val = ucontrol->value.enumerated.item[0]; + + if (!pdata || !pdata->adc2_sel_gpio_p) { + pr_err("%s: adc2_sel_gpio is invalid\n", __func__); + return -EINVAL; + } + + //TODO: need to fix adc2 amplitude less than 3db issue +// external_enable_dual_adc_gpio(pdata->adc2_sel_gpio_p, !!(val)); + pr_info("external_amic2_sel_put %u \n", val); + + return snd_soc_dapm_put_enum_double(kcontrol, ucontrol); +} + +static const char *const external_AMIC2_enum_text[] = {"default", "Dual_ADC"}; + +static SOC_ENUM_SINGLE_VIRT_DECL(external_AMIC2_enum, external_AMIC2_enum_text); + +static const struct snd_kcontrol_new ext_amc2_mux = + SOC_DAPM_ENUM_EXT("External AMIC2 sel", external_AMIC2_enum, + snd_soc_dapm_get_enum_double, external_amic2_sel_put); + + static const struct snd_soc_dapm_widget msm_dapm_widgets[] = { SND_SOC_DAPM_SUPPLY("MCLK", SND_SOC_NOPM, 0, 0, @@ -3389,6 +3479,19 @@ static const struct snd_soc_dapm_widget msm_dapm_widgets_tavil[] = { SND_SOC_DAPM_MIC("Digital Mic3", NULL), SND_SOC_DAPM_MIC("Digital Mic4", NULL), SND_SOC_DAPM_MIC("Digital Mic5", NULL), + SND_SOC_DAPM_MIC("Headset Mic2", NULL), +}; + +static const struct snd_soc_dapm_widget msm_dualadc_dapm_widgets[] = { + SND_SOC_DAPM_MUX("External AMIC2 Mux", SND_SOC_NOPM, 0, 0, &ext_amc2_mux), + SND_SOC_DAPM_INPUT("AMIC2_EXT_0"), + SND_SOC_DAPM_INPUT("AMIC2_EXT_1"), +}; + +static const struct snd_soc_dapm_route msm_dualadc_dapm_routes[] = { + {"AMIC2", NULL, "External AMIC2 Mux"}, + {"External AMIC2 Mux", "default", "AMIC2_EXT_0"}, + {"External AMIC2 Mux", "Dual_ADC", "AMIC2_EXT_1"}, }; static inline int param_is_mask(int p) @@ -3869,10 +3972,108 @@ static bool msm_usbc_swap_gnd_mic(struct snd_soc_codec *codec, bool active) struct msm_asoc_mach_data *pdata = snd_soc_card_get_drvdata(card); - if (!pdata->fsa_handle) - return false; + struct pinctrl_state *en2_pinctrl_active; + struct pinctrl_state *en2_pinctrl_sleep; + int value = 0; + bool ret = 0; + int oldv; + + if (wcd_mbhc_cfg.use_fsa4476_gpio != 0) { + if (!pdata->usbc_en2_gpio_p) { + if (active) { + /* if active and usbc_en2_gpio undefined, get pin */ + pdata->usbc_en2_gpio_p = devm_pinctrl_get(card->dev); + if (IS_ERR_OR_NULL(pdata->usbc_en2_gpio_p)) { + dev_err(card->dev, + "%s: Can't get EN2 gpio pinctrl:%ld\n", + __func__, + PTR_ERR(pdata->usbc_en2_gpio_p)); + pdata->usbc_en2_gpio_p = NULL; + return false; + } + } else + /* if not active and usbc_en2_gpio undefined, return */ + return false; + } + + pdata->usbc_en2_gpio = of_get_named_gpio(card->dev->of_node, + "qcom,usbc-analog-en2-gpio", 0); + if (!gpio_is_valid(pdata->usbc_en2_gpio)) { + dev_err(card->dev, "%s, property %s not in node %s", + __func__, "qcom,usbc-analog-en2-gpio", + card->dev->of_node->full_name); + return false; + } + + en2_pinctrl_active = pinctrl_lookup_state( + pdata->usbc_en2_gpio_p, "aud_active"); + if (IS_ERR_OR_NULL(en2_pinctrl_active)) { + dev_err(card->dev, + "%s: Cannot get aud_active pinctrl state:%ld\n", + __func__, PTR_ERR(en2_pinctrl_active)); + ret = false; + goto err_lookup_state; + } - return fsa4480_switch_event(pdata->fsa_handle, FSA_MIC_GND_SWAP); + en2_pinctrl_sleep = pinctrl_lookup_state( + pdata->usbc_en2_gpio_p, "aud_sleep"); + if (IS_ERR_OR_NULL(en2_pinctrl_sleep)) { + dev_err(card->dev, + "%s: Cannot get aud_sleep pinctrl state:%ld\n", + __func__, PTR_ERR(en2_pinctrl_sleep)); + ret = false; + goto err_lookup_state; + } + + /* if active and usbc_en2_gpio_p defined, swap using usbc_en2_gpio_p */ + if (active) { + dev_dbg(codec->dev, "%s: enter\n", __func__); + oldv = tavil_mb_pull_down(codec, true, 0); + if (wcd_mbhc_cfg.usbc_analog_cfg.euro_us_hw_switch_gpio_p) { + value = gpio_get_value_cansleep(pdata->usbc_en2_gpio); + if (value) + msm_cdc_pinctrl_select_sleep_state( + wcd_mbhc_cfg.usbc_analog_cfg.euro_us_hw_switch_gpio_p); + else + msm_cdc_pinctrl_select_active_state( + wcd_mbhc_cfg.usbc_analog_cfg.euro_us_hw_switch_gpio_p); + } + else if (pdata->usbc_en2_gpio_p) { + value = gpio_get_value_cansleep(pdata->usbc_en2_gpio); + if (value) + pinctrl_select_state(pdata->usbc_en2_gpio_p, + en2_pinctrl_sleep); + else + pinctrl_select_state(pdata->usbc_en2_gpio_p, + en2_pinctrl_active); + } else if (pdata->usbc_en2_gpio >= 0) { + value = gpio_get_value_cansleep(pdata->usbc_en2_gpio); + gpio_set_value_cansleep(pdata->usbc_en2_gpio, !value); + } + tavil_mb_pull_down(codec, false, oldv); + pr_info("%s: swap select switch %d to %d\n", __func__, + value, !value); + ret = true; + } else { + /* if not active, release usbc_en2_gpio_p pin */ + pinctrl_select_state(pdata->usbc_en2_gpio_p, + en2_pinctrl_sleep); + } + } else { + if (!pdata->fsa_handle) + return false; + + return fsa4480_switch_event(pdata->fsa_handle, FSA_MIC_GND_SWAP); + } + + +err_lookup_state: + if (wcd_mbhc_cfg.use_fsa4476_gpio != 0) { + devm_pinctrl_put(pdata->usbc_en2_gpio_p); + pdata->usbc_en2_gpio_p = NULL; + } + + return ret; } static bool msm_swap_gnd_mic(struct snd_soc_codec *codec, bool active) @@ -4145,6 +4346,15 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) ARRAY_SIZE(wcd_audio_paths)); } + if (pdata->adc2_sel_gpio_p) { + pr_info("add the External AMIC2 Mux\n"); + snd_soc_dapm_new_controls(dapm, msm_dualadc_dapm_widgets, + ARRAY_SIZE(msm_dualadc_dapm_widgets)); + + snd_soc_dapm_add_routes(dapm, msm_dualadc_dapm_routes, + ARRAY_SIZE(msm_dualadc_dapm_routes)); + } + snd_soc_dapm_ignore_suspend(dapm, "Handset Mic"); snd_soc_dapm_ignore_suspend(dapm, "Digital Mic0"); snd_soc_dapm_ignore_suspend(dapm, "Digital Mic1"); @@ -4165,6 +4375,12 @@ static int msm_audrx_init(struct snd_soc_pcm_runtime *rtd) snd_soc_dapm_ignore_suspend(dapm, "WDMA3_OUT"); if (!strcmp(dev_name(codec_dai->dev), "tavil_codec")) { + if (pdata->adc2_sel_gpio_p) { + snd_soc_dapm_ignore_suspend(dapm, "AMIC2"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC2_EXT_0"); + snd_soc_dapm_ignore_suspend(dapm, "AMIC2_EXT_1"); + snd_soc_dapm_ignore_suspend(dapm, "Headset Mic2"); + } snd_soc_dapm_ignore_suspend(dapm, "Headset Mic"); snd_soc_dapm_ignore_suspend(dapm, "ANCRight Headset Mic"); snd_soc_dapm_ignore_suspend(dapm, "ANCLeft Headset Mic"); @@ -4306,13 +4522,13 @@ static void *def_wcd_mbhc_cal(void) (sizeof(btn_cfg->_v_btn_low[0]) * btn_cfg->num_btn); btn_high[0] = 75; - btn_high[1] = 150; - btn_high[2] = 237; - btn_high[3] = 500; - btn_high[4] = 500; - btn_high[5] = 500; - btn_high[6] = 500; - btn_high[7] = 500; + btn_high[1] = 260; + btn_high[2] = 750; + btn_high[3] = 750; + btn_high[4] = 750; + btn_high[5] = 750; + btn_high[6] = 750; + btn_high[7] = 750; return wcd_mbhc_cal; } @@ -5056,6 +5272,11 @@ static int msm_mi2s_snd_startup(struct snd_pcm_substream *substream) __func__, ret_pinctrl); } } + + snd_soc_codec_set_sysclk(rtd->codec_dai->codec, 0, 0, + mi2s_clk[index].clk_freq_in_hz, + SND_SOC_CLOCK_IN); + clk_off: if (ret < 0) msm_mi2s_set_sclk(substream, false); @@ -5867,6 +6088,36 @@ static struct snd_soc_dai_link msm_common_misc_fe_dai_links[] = { .ignore_pmdown_time = 1, .id = MSM_FRONTEND_DAI_MULTIMEDIA31, }, + { + .name = "Quaternary MI2S_RX Hostless Playback", + .stream_name = "Quaternary MI2S_RX Hostless Playback", + .cpu_dai_name = "QUAT_MI2S_RX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_playback = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, + { + .name = "Quaternary MI2S_TX Hostless Capture", + .stream_name = "Quaternary MI2S_TX Hostless Capture", + .cpu_dai_name = "QUAT_MI2S_TX_HOSTLESS", + .platform_name = "msm-pcm-hostless", + .dynamic = 1, + .dpcm_capture = 1, + .trigger = {SND_SOC_DPCM_TRIGGER_POST, + SND_SOC_DPCM_TRIGGER_POST}, + .no_host_mode = SND_SOC_DAI_LINK_NO_HOST, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + .codec_dai_name = "snd-soc-dummy-dai", + .codec_name = "snd-soc-dummy", + }, }; static struct snd_soc_dai_link msm_common_be_dai_links[] = { @@ -6664,21 +6915,6 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { .ops = &msm_mi2s_be_ops, .ignore_suspend = 1, }, - { - .name = LPASS_BE_QUAT_MI2S_RX, - .stream_name = "Quaternary MI2S Playback", - .cpu_dai_name = "msm-dai-q6-mi2s.3", - .platform_name = "msm-pcm-routing", - .codec_name = "msm-stub-codec.1", - .codec_dai_name = "msm-stub-rx", - .no_pcm = 1, - .dpcm_playback = 1, - .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, - .be_hw_params_fixup = msm_be_hw_params_fixup, - .ops = &msm_mi2s_be_ops, - .ignore_suspend = 1, - .ignore_pmdown_time = 1, - }, { .name = LPASS_BE_QUAT_MI2S_TX, .stream_name = "Quaternary MI2S Capture", @@ -6725,6 +6961,25 @@ static struct snd_soc_dai_link msm_mi2s_be_dai_links[] = { }; +static struct snd_soc_dai_link quat_mi2s_rx_cs35l41_dai_links[] = { + { + .name = LPASS_BE_QUAT_MI2S_RX, + .stream_name = "Quaternary MI2S Playback", + .cpu_dai_name = "msm-dai-q6-mi2s.3", + .platform_name = "msm-pcm-routing", + .codec_name = CS35L41_CODEC_NAME, + .codec_dai_name = "cs35l41-pcm", + .no_pcm = 1, + .dpcm_playback = 1, + .id = MSM_BACKEND_DAI_QUATERNARY_MI2S_RX, + .be_hw_params_fixup = msm_be_hw_params_fixup, + .ops = &msm_mi2s_be_ops, + .ignore_suspend = 1, + .ignore_pmdown_time = 1, + }, +}; + + static struct snd_soc_dai_link msm_auxpcm_be_dai_links[] = { /* Primary AUX PCM Backend DAI Links */ { @@ -6887,6 +7142,7 @@ static struct snd_soc_dai_link msm_tavil_dai_links[ ARRAY_SIZE(msm_wcn_be_dai_links) + ARRAY_SIZE(ext_disp_be_dai_link) + ARRAY_SIZE(msm_mi2s_be_dai_links) + + ARRAY_SIZE(quat_mi2s_rx_cs35l41_dai_links) + ARRAY_SIZE(msm_auxpcm_be_dai_links)]; static int msm_snd_card_tavil_late_probe(struct snd_soc_card *card) @@ -6895,6 +7151,12 @@ static int msm_snd_card_tavil_late_probe(struct snd_soc_card *card) struct snd_soc_pcm_runtime *rtd; int ret = 0; void *mbhc_calibration; +#ifdef CONFIG_SND_SOC_CS35L41_FOR_CEPH + struct snd_soc_dai_link *dai_link; + struct snd_soc_codec *cs35l41_codec; + struct snd_soc_dapm_context * cs35l41_dapm; +#endif + rtd = snd_soc_get_pcm_runtime(card, be_dl_name); if (!rtd) { @@ -6917,6 +7179,26 @@ static int msm_snd_card_tavil_late_probe(struct snd_soc_card *card) __func__, ret); goto err_hs_detect; } +#ifdef CONFIG_SND_SOC_CS35L41_FOR_CEPH + dai_link = rtd->dai_link; + if (dai_link && dai_link->codec_name) { + if (!strcmp(dai_link->codec_name, CS35L41_CODEC_NAME)) { + dev_info(card->dev, "%s: found codec[%s]\n", __func__, CS35L41_CODEC_NAME); + cs35l41_codec = rtd->codec; + cs35l41_dapm = snd_soc_codec_get_dapm(cs35l41_codec); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "AMP Playback"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "AMP Capture"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "DSP1"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "Main AMP"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "ASPRX1"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "ASPRX2"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "ASPTX1"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "ASPTX2"); + snd_soc_dapm_ignore_suspend(cs35l41_dapm, "SPK"); + snd_soc_dapm_sync(cs35l41_dapm); + } + } +#endif return 0; err_hs_detect: @@ -7281,6 +7563,11 @@ static struct snd_soc_card *populate_snd_card_dailinks(struct device *dev) msm_mi2s_be_dai_links, sizeof(msm_mi2s_be_dai_links)); total_links += ARRAY_SIZE(msm_mi2s_be_dai_links); + + memcpy(msm_tavil_dai_links + total_links, + quat_mi2s_rx_cs35l41_dai_links, + sizeof(quat_mi2s_rx_cs35l41_dai_links)); + total_links += ARRAY_SIZE(quat_mi2s_rx_cs35l41_dai_links); } ret = of_property_read_u32(dev->of_node, @@ -7618,6 +7905,26 @@ static int msm_asoc_machine_probe(struct platform_device *pdev) platform_set_drvdata(pdev, card); snd_soc_card_set_drvdata(card, pdata); + pdata->adc2_sel_gpio_p = of_parse_phandle(pdev->dev.of_node, + "qcom,adc2-switch-gpio", 0); + if (!pdata->adc2_sel_gpio_p) { + dev_err(&pdev->dev, "property %s not detected in node %s", + "qcom,adc2-switch-gpio", + pdev->dev.of_node->full_name); + } + + wcd_mbhc_cfg.dual_adc_gpio_node = pdata->adc2_sel_gpio_p; + wcd_mbhc_cfg.enable_dual_adc_gpio = external_enable_dual_adc_gpio; + pr_info("pdata->adc2_sel_gpio_p = %lx\n", (unsigned long)pdata->adc2_sel_gpio_p); + + pdata->usbc_en2_gpio = of_get_named_gpio(card->dev->of_node, + "qcom,usbc-analog-en2-gpio", 0); + if (!gpio_is_valid(pdata->usbc_en2_gpio)) { + dev_err(card->dev, "%s, property %s not in node %s", + __func__, "qcom,usbc-analog-en2-gpio", + card->dev->of_node->full_name); + } + ret = snd_soc_of_parse_card_name(card, "qcom,model"); if (ret) { dev_err(&pdev->dev, "parse card name failed, err:%d\n", diff --git a/techpack/audio/config/sm8150auto.conf b/techpack/audio/config/sm8150auto.conf index e0e49e7757ba..13615d017b71 100644 --- a/techpack/audio/config/sm8150auto.conf +++ b/techpack/audio/config/sm8150auto.conf @@ -39,3 +39,9 @@ CONFIG_SND_SOC_MSM_STUB=m CONFIG_MSM_AVTIMER=m CONFIG_SND_SOC_MSM_HDMI_CODEC_RX=m CONFIG_VOICE_MHI=m +CONFIG_SND_SOC_TAS2557=m +CONFIG_TAS2557_REGMAP=m +CONFIG_TAS2557_CODEC=m +CONFIG_TAS2557_MISC=m +CONFIG_SND_SOC_CS35L41=m +CONFIG_MSM_CSPL=y diff --git a/techpack/audio/config/sm8150autoconf.h b/techpack/audio/config/sm8150autoconf.h index e0eea9d99c5e..c63ceba7d205 100644 --- a/techpack/audio/config/sm8150autoconf.h +++ b/techpack/audio/config/sm8150autoconf.h @@ -51,3 +51,9 @@ #define CONFIG_MSM_AVTIMER 1 #define CONFIG_SND_SOC_MSM_HDMI_CODEC_RX 1 #define CONFIG_VOICE_MHI 1 +#define CONFIG_SND_SOC_TAS2557 1 +#define CONFIG_TAS2557_REGMAP 1 +#define CONFIG_TAS2557_CODEC 1 +#define CONFIG_TAS2557_MISC 1 +#define CONFIG_SND_SOC_CS35L41 1 +#define CONFIG_MSM_CSPL 1 diff --git a/techpack/audio/dsp/Android.mk b/techpack/audio/dsp/Android.mk deleted file mode 100644 index b23c2743e0d9..000000000000 --- a/techpack/audio/dsp/Android.mk +++ /dev/null @@ -1,94 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,sdm845),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m -endif - -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile atoll $(MSMSTEPPE) $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=q6_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_q6.ko -LOCAL_MODULE_KBUILD_NAME := q6_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_usf.ko -LOCAL_MODULE_KBUILD_NAME := usf_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_adsp_loader.ko -LOCAL_MODULE_KBUILD_NAME := adsp_loader_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_q6_notifier.ko -LOCAL_MODULE_KBUILD_NAME := q6_notifier_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_q6_pdr.ko -LOCAL_MODULE_KBUILD_NAME := q6_pdr_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/dsp/Kbuild b/techpack/audio/dsp/Kbuild index 17d883a43b01..cb2277692316 100644 --- a/techpack/audio/dsp/Kbuild +++ b/techpack/audio/dsp/Kbuild @@ -102,6 +102,13 @@ ifdef CONFIG_SND_SOC_MSM_QDSP6V2_INTF Q6_OBJS += msm_audio_ion.o Q6_OBJS += avtimer.o Q6_OBJS += q6_init.o + Q6_OBJS += apr_elliptic.o + Q6_OBJS += elliptic/elliptic.o + Q6_OBJS += elliptic/elliptic_sysfs.o + Q6_OBJS += elliptic/elliptic_mixer_controls.o + Q6_OBJS += elliptic/io_modules/msm/elliptic_data_msm_io.o + Q6_OBJS += elliptic/io_modules/userspace/elliptic_data_userspace_io.o + Q6_OBJS += elliptic/io_modules/userspace/elliptic_data_userspace_ctrl.o endif ifdef CONFIG_XT_LOGGING @@ -140,6 +147,10 @@ ifdef CONFIG_VOICE_MHI Q6_OBJS += voice_mhi.o endif +ifdef CONFIG_MSM_CSPL + Q6_OBJS += msm-cirrus-playback.o +endif + LINUX_INC += -Iinclude/linux INCS += $(COMMON_INC) \ @@ -210,6 +221,3 @@ q6_pdr_dlkm-y := $(QDSP6_PDR_OBJS) obj-$(CONFIG_MSM_QDSP6_NOTIFIER) += q6_notifier_dlkm.o q6_notifier_dlkm-y := $(QDSP6_NOTIFIER_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/dsp/apr_elliptic.c b/techpack/audio/dsp/apr_elliptic.c new file mode 100755 index 000000000000..b3d67edfba09 --- /dev/null +++ b/techpack/audio/dsp/apr_elliptic.c @@ -0,0 +1,452 @@ +/** + * Elliptic Labs + */ + +#include +#include +#include +#include +#include +#include +#include "../asoc/msm-pcm-routing-v2.h" +#include +#include +#include +#include +#include +#include + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +enum { + HALL_SLIDER_UP = 4, + HALL_SLIDER_DOWN = 5, + HALL_SLIDING = 6, +}; + +enum driver_sensor_type { + DRIVER_SENSOR_HALL = 35, +}; + +struct driver_sensor_event { + enum driver_sensor_type type; + union { + int32_t event; + int32_t reserved[2]; + }; +}; + + + +static int afe_set_parameter(int port, + int param_id, + int module_id, + struct afe_ultrasound_set_params_t *prot_config, + uint32_t length) +{ + struct afe_port_cmd_set_param_v2 *set_param_v2 = NULL; + uint32_t set_param_v2_size = sizeof(struct afe_port_cmd_set_param_v2); + struct afe_port_cmd_set_param_v3 *set_param_v3 = NULL; + uint32_t set_param_v3_size = sizeof(struct afe_port_cmd_set_param_v3); + struct param_hdr_v3 param_hdr = {0}; + u16 port_id = 0; + int index = 0; + u8 *packed_param_data = NULL; + int packed_data_size = sizeof(union param_hdrs) + length; + int ret = 0; + + pr_debug("[ELUS]: inside %s\n", __func__); + + port_id = q6audio_get_port_id(port); + ret = q6audio_validate_port(port_id); + if (ret < 0) { + pr_err("%s: Not a valid port id = 0x%x ret %d\n", __func__, + port_id, ret); + return -EINVAL; + } + index = q6audio_get_port_index(port); + + param_hdr.module_id = module_id; + param_hdr.instance_id = INSTANCE_ID_0; + param_hdr.param_id = param_id; + param_hdr.param_size = length; + pr_debug("[ELUS]: param_size %d\n", length); + + packed_param_data = kzalloc(packed_data_size, GFP_KERNEL); + if (packed_param_data == NULL) + return -ENOMEM; + + ret = q6common_pack_pp_params(packed_param_data, ¶m_hdr, (u8 *)prot_config, + &packed_data_size); + if (ret) { + pr_err("%s: Failed to pack param header and data, error %d\n", + __func__, ret); + goto fail_cmd; + } + + if (q6common_is_instance_id_supported()) { + set_param_v3_size += packed_data_size; + set_param_v3 = kzalloc(set_param_v3_size, GFP_KERNEL); + if (set_param_v3 == NULL) { + ret = -ENOMEM; + goto fail_cmd; + } + + set_param_v3->apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + set_param_v3->apr_hdr.pkt_size = sizeof(struct afe_port_cmd_set_param_v3) + + packed_data_size; + set_param_v3->apr_hdr.src_port = 0; + set_param_v3->apr_hdr.dest_port = 0; + set_param_v3->apr_hdr.token = index; + set_param_v3->apr_hdr.opcode = AFE_PORT_CMD_SET_PARAM_V3; + set_param_v3->port_id = port_id; + set_param_v3->payload_size = packed_data_size; + memcpy(&set_param_v3->param_data, packed_param_data, + packed_data_size); + + atomic_set(elus_afe.ptr_state, 1); + ret = apr_send_pkt(*elus_afe.ptr_apr, (uint32_t *) set_param_v3); + } else { + set_param_v2_size += packed_data_size; + set_param_v2 = kzalloc(set_param_v2_size, GFP_KERNEL); + if (set_param_v2 == NULL) { + ret = -ENOMEM; + goto fail_cmd; + } + + set_param_v2->apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + set_param_v2->apr_hdr.pkt_size = sizeof(struct afe_port_cmd_set_param_v2) + + packed_data_size; + set_param_v2->apr_hdr.src_port = 0; + set_param_v2->apr_hdr.dest_port = 0; + set_param_v2->apr_hdr.token = index; + set_param_v2->apr_hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + set_param_v2->port_id = port_id; + set_param_v2->payload_size = packed_data_size; + memcpy(&set_param_v2->param_data, packed_param_data, + packed_data_size); + + atomic_set(elus_afe.ptr_state, 1); + ret = apr_send_pkt(*elus_afe.ptr_apr, (uint32_t *) set_param_v2); + } + if (ret < 0) { + pr_err("%s: Setting param for port %d param[0x%x]failed\n", + __func__, port, param_id); + goto fail_cmd; + } + ret = wait_event_timeout(elus_afe.ptr_wait[index], + (atomic_read(elus_afe.ptr_state) == 0), + msecs_to_jiffies(elus_afe.timeout_ms*10)); + if (!ret) { + pr_err("%s: wait_event timeout\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + if (atomic_read(elus_afe.ptr_status) != 0) { + pr_err("%s: set param cmd failed\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + ret = 0; +fail_cmd: + pr_debug("%s param_id %x status %d\n", __func__, param_id, ret); + kfree(set_param_v2); + kfree(set_param_v3); + kfree(packed_param_data); + return ret; +} + + +int32_t ultrasound_apr_set_parameter(int32_t port_id, uint32_t param_id, + u8 *user_params, int32_t length) { + + int32_t ret = 0; + uint32_t module_id; + + if (port_id == ELLIPTIC_PORT_ID) + module_id = ELLIPTIC_ULTRASOUND_MODULE_TX; + else + module_id = ELLIPTIC_ULTRASOUND_MODULE_RX; + + ret = afe_set_parameter(port_id, + param_id, module_id, + (struct afe_ultrasound_set_params_t *)user_params, + length); + + return ret; +} + +static int32_t process_version_msg(uint32_t *payload, uint32_t payload_size) +{ + struct elliptic_shared_data_block *data_block = NULL; + size_t copy_size = 0; + int32_t ret = -1; + + pr_err("[ELUS]: %s() size:%d\n", __func__, payload_size); + + if (payload_size >= ELLIPTIC_VERSION_INFO_SIZE) { + pr_debug("[ELUS]: elliptic_version copied to local AP cache"); + data_block = + elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_VERSION_INFO); + copy_size = min_t(size_t, data_block->size, + (size_t)ELLIPTIC_VERSION_INFO_SIZE); + + memcpy((u8 *)data_block->buffer, + &payload[3], copy_size); + ret = (int32_t)copy_size; + } + return ret; +} + +static int32_t process_branch_msg(uint32_t *payload, uint32_t payload_size) +{ + struct elliptic_shared_data_block *data_block = NULL; + size_t copy_size = 0; + int32_t ret = -1; + + pr_err("[ELUS]: %s() size:%d\n", __func__, payload_size); + + if (payload_size >= ELLIPTIC_BRANCH_INFO_SIZE) { + pr_debug("[ELUS]: elliptic_branch copied to local AP cache"); + data_block = + elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_BRANCH_INFO); + copy_size = min_t(size_t, data_block->size, + (size_t)ELLIPTIC_BRANCH_INFO_MAX_SIZE); + + memcpy((u8 *)data_block->buffer, + &payload[3], copy_size); + ret = (int32_t)copy_size; + } + return ret; +} + +static int32_t process_tag_msg(uint32_t *payload, uint32_t payload_size) +{ + struct elliptic_shared_data_block *data_block = NULL; + size_t copy_size = 0; + int32_t ret = -1; + + pr_err("[ELUS]: %s() size:%d\n", __func__, payload_size); + + if (payload_size >= ELLIPTIC_TAG_INFO_SIZE) { + pr_debug("[ELUS]: elliptic_tag copied to local AP cache"); + data_block = + elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_TAG_INFO); + copy_size = min_t(size_t, data_block->size, + (size_t)ELLIPTIC_TAG_INFO_SIZE); + + memcpy((u8 *)data_block->buffer, + &payload[3], copy_size); + ret = (int32_t)copy_size; + } + return ret; +} + +static int32_t process_calibration_msg(uint32_t *payload, uint32_t payload_size) +{ + struct elliptic_shared_data_block *data_block = NULL; + size_t copy_size = 0; + int32_t ret = -1; + + pr_err("[ELUS]: %s() size:%d\n", __func__, payload_size); + + if (payload_size >= ELLIPTIC_CALIBRATION_DATA_SIZE) { + pr_debug("[ELUS]: calibration_data copied to local AP cache"); + + data_block = elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_CALIBRATION_DATA); + copy_size = min_t(size_t, data_block->size, + (size_t)ELLIPTIC_CALIBRATION_DATA_SIZE); + + memcpy((u8 *)data_block->buffer, + &payload[3], copy_size); + elliptic_set_calibration_data((u8 *)&payload[3], copy_size); + ret = (int32_t)copy_size; + } + return ret; +} + +static int32_t process_calibration_v2_msg(uint32_t *payload, uint32_t payload_size) +{ + struct elliptic_shared_data_block *data_block = NULL; + size_t copy_size = 0; + int32_t ret = -1; + + pr_err("[ELUS]: %s() size:%d\n", __func__, payload_size); + + if (payload_size >= ELLIPTIC_CALIBRATION_V2_DATA_SIZE) { + pr_debug("[ELUS]: calibration_data copied to local AP cache"); + + data_block = elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_CALIBRATION_V2_DATA); + copy_size = min_t(size_t, data_block->size, + (size_t)ELLIPTIC_CALIBRATION_V2_DATA_SIZE); + + memcpy((u8 *)data_block->buffer, + &payload[3], copy_size); + elliptic_set_calibration_data((u8 *)&payload[3], copy_size); + ret = (int32_t)copy_size; + } + return ret; +} + +static int32_t process_ml_msg(uint32_t *payload, uint32_t payload_size) +{ + struct elliptic_shared_data_block *data_block = NULL; + size_t copy_size = 0; + int32_t ret = -1; + + pr_err("[ELUS]: %s() size:%d\n", __func__, payload_size); + + if (payload_size >= ELLIPTIC_ML_DATA_SIZE) { + pr_debug("[ELUS]: ml_data copied to local AP cache"); + + data_block = elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_ML_DATA); + copy_size = min_t(size_t, data_block->size, + (size_t)ELLIPTIC_ML_DATA_SIZE); + + memcpy((u8 *)data_block->buffer, + &payload[3], copy_size); + ret = (int32_t)copy_size; + } + return ret; +} + +static int32_t process_diagnostics_msg(uint32_t *payload, uint32_t payload_size) +{ + struct elliptic_shared_data_block *data_block = NULL; + size_t copy_size = 0; + int32_t ret = -1; + + pr_err("[ELUS]: %s() size:%d\n", __func__, payload_size); + + if (payload_size >= ELLIPTIC_DIAGNOSTICS_DATA_SIZE) { + pr_debug("[ELUS]: diagnostics_data copied to local AP cache"); + + data_block = elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_DIAGNOSTICS_DATA); + copy_size = min_t(size_t, data_block->size, + (size_t)ELLIPTIC_DIAGNOSTICS_DATA_SIZE); + + memcpy((u8 *)data_block->buffer, + &payload[3], copy_size); + ret = (int32_t)copy_size; + } + return ret; +} + +static int32_t process_sensorhub_msg(uint32_t *payload, uint32_t payload_size) +{ + int32_t ret = 0; + + pr_err("[ELUS]: %s, paramId:%u, size:%d\n", + __func__, payload[1], payload_size); + + return ret; +} + +int32_t elliptic_process_apr_payload(uint32_t *payload) +{ + uint32_t payload_size = 0; + int32_t ret = -1; + + if (payload[0] == ELLIPTIC_ULTRASOUND_MODULE_TX) { + /* payload format + * payload[0] = Module ID + * payload[1] = Param ID + * payload[2] = LSB - payload size + * MSB - reserved(TBD) + * payload[3] = US data payload starts from here + */ + payload_size = payload[2] & 0xFFFF; + + switch (payload[1]) { + case ELLIPTIC_ULTRASOUND_PARAM_ID_ENGINE_VERSION: + ret = process_version_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_BUILD_BRANCH: + ret = process_branch_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_TAG: + ret = process_tag_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_CALIBRATION_DATA: + ret = process_calibration_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_CALIBRATION_V2_DATA: + ret = process_calibration_v2_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_ML_DATA: + ret = process_ml_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_DIAGNOSTICS_DATA: + ret = process_diagnostics_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_SENSORHUB: + ret = process_sensorhub_msg(payload, payload_size); + break; + case ELLIPTIC_ULTRASOUND_PARAM_ID_ENGINE_DATA: + ret = elliptic_data_push( + ELLIPTIC_ALL_DEVICES, + (const char *)&payload[3], + (size_t)payload_size, + ELLIPTIC_DATA_PUSH_FROM_KERNEL); + + if (ret != 0) { + pr_err("[ELUS] : failed to push apr payload to elliptic device"); + return ret; + } + ret = payload_size; + break; + default: + { + pr_err("[ELUS] : elliptic_process_apr_payload, Illegal paramId:%u", payload[1]); + } + break; + } + } else { + pr_debug("[ELUS]: Invalid Ultrasound Module ID %d\n", + payload[0]); + } + return ret; +} + +int elliptic_set_hall_state(int state) +{ + struct driver_sensor_event dse; + int ret = -1; + + dse.type = DRIVER_SENSOR_HALL; + + switch (state) { + case 0: + dse.event = HALL_SLIDER_UP; + break; + case 1: + dse.event = HALL_SLIDER_DOWN; + break; + case 2: + dse.event = HALL_SLIDING; + break; + default: + pr_err("%s Invalid HALL state:%d\n", __func__, state); + return ret; + } + + ret = afe_set_parameter(ELLIPTIC_PORT_ID, + 2, ELLIPTIC_ULTRASOUND_MODULE_TX, + (struct afe_ultrasound_set_params_t *)&dse, + sizeof(dse)); + return ret; +} +EXPORT_SYMBOL(elliptic_set_hall_state); diff --git a/techpack/audio/dsp/codecs/Android.mk b/techpack/audio/dsp/codecs/Android.mk deleted file mode 100644 index 622e46559da8..000000000000 --- a/techpack/audio/dsp/codecs/Android.mk +++ /dev/null @@ -1,62 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,sdm845),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m -endif - -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile $(MSMSTEPPE) atoll $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=native_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_native.ko -LOCAL_MODULE_KBUILD_NAME := native_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/dsp/codecs/Kbuild b/techpack/audio/dsp/codecs/Kbuild index ab4195a85d64..b95a8d606630 100644 --- a/techpack/audio/dsp/codecs/Kbuild +++ b/techpack/audio/dsp/codecs/Kbuild @@ -157,6 +157,3 @@ endif # Module information used by KBuild framework obj-$(CONFIG_MSM_QDSP6V2_CODECS) += native_dlkm.o native_dlkm-y := $(NATIVE_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/dsp/elliptic/elliptic.c b/techpack/audio/dsp/elliptic/elliptic.c new file mode 100755 index 000000000000..2466d6185315 --- /dev/null +++ b/techpack/audio/dsp/elliptic/elliptic.c @@ -0,0 +1,800 @@ +/** +* Copyright Elliptic Labs +* +*/ +/* #define DEBUG */ +#include +#include +#include +/* includes the file structure, that is, file open read close */ +#include + +/* include the character device, makes cdev avilable */ +#include +#include + +/* includes copy_user vice versa */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include + + +/* Alternative mechanism to load calibration data. +* Read calibration data during driver initialization +* and send message to the DSP +* +* #define ELLIPTIC_LOAD_CALIBRATION_DATA_FROM_FILESYSTEM 1 +*/ +#ifdef ELLIPTIC_LOAD_CALIBRATION_DATA_FROM_FILESYSTEM +#include +#include +#include +#endif + +static struct elliptic_device *elliptic_devices; + +/* Global variable for the device class*/ +struct class *elliptic_class; + +typedef uint32_t el_fifo_size_t; + +/* Major number provided by the kernel*/ +static dev_t elliptic_major; + +static struct wakeup_source *wake_source; + + +void elliptic_data_cancel(struct elliptic_data *elliptic_data) +{ + atomic_set(&elliptic_data->abort_io, 1); + wake_up_interruptible(&elliptic_data->fifo_isr_not_empty); +} + +void elliptic_data_reset_debug_counters(struct elliptic_data *elliptic_data) +{ + elliptic_data->isr_fifo_discard = 0; +} + +void elliptic_data_print_debug_counters(struct elliptic_data *elliptic_data) +{ + if (elliptic_data->isr_fifo_discard > 0) { + EL_PRINT_E("isr fifo discarded %u frames", + elliptic_data->isr_fifo_discard); + } + + if (elliptic_data->userspace_read_total != + elliptic_data->isr_write_total) { + EL_PRINT_I("user space reads / isr writes : %u / %u", + elliptic_data->userspace_read_total, + elliptic_data->isr_write_total); + } + + EL_PRINT_I("total isr fifo discarded frame count : %u", + elliptic_data->isr_fifo_discard_total); +} + +void elliptic_data_update_debug_counters(struct elliptic_data + *elliptic_data) +{ + elliptic_data->isr_fifo_discard_total += + elliptic_data->isr_fifo_discard; +} + + +/* spin lock for isr must be held prior to calling */ +static void elliptic_data_flush_isr_fifo(struct elliptic_data + *elliptic_data) +{ + kfifo_reset(&elliptic_data->fifo_isr); +} + +/* spin lock for isr must be held prior to calling */ +static void elliptic_data_isr_fifo_pop(struct elliptic_data + *elliptic_data, size_t size) +{ + unsigned int fifo_result; + static uint8_t temp_buffer[ELLIPTIC_MSG_BUF_SIZE]; + + if (size > ELLIPTIC_MSG_BUF_SIZE) + EL_PRINT_E("pop size %zu too large", size); + + fifo_result = kfifo_out(&elliptic_data->fifo_isr, + temp_buffer, size); + + if (size != fifo_result) + EL_PRINT_E("failed to pop element"); +} + + +int elliptic_notify_gain_change_msg(int component_id, int gaindb) +{ + int32_t msg[3] = {ESCPT_COMPONENT_GAIN_CHANGE, component_id, gaindb}; + + return elliptic_data_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} + +/* inode refers to the actual file on disk */ +static int device_open(struct inode *inode, struct file *filp) +{ + unsigned int major; + unsigned int minor; + struct elliptic_device *dev; + struct elliptic_data *elliptic_data; + + major = imajor(inode); + minor = iminor(inode); + + if (major != elliptic_major || minor < 0 + || minor >= ELLIPTIC_NUM_DEVICES) { + EL_PRINT_W("no device found with minor=%d and major=%d", + major, minor); + return -ENODEV; /* No such device */ + } + + dev = NULL; + dev = &elliptic_devices[minor]; + filp->private_data = dev; + + if (inode->i_cdev != &dev->cdev) { + EL_PRINT_W("dev pointer mismatch"); + return -ENODEV; /* No such device */ + } + + if (down_interruptible(&dev->sem) != 0) { + EL_PRINT_E("the device has been opened, unable to open lock"); + return -EINVAL; + } + + elliptic_data = &dev->el_data; + spin_lock(&elliptic_data->fifo_isr_spinlock); + elliptic_data_flush_isr_fifo(elliptic_data); + spin_unlock(&elliptic_data->fifo_isr_spinlock); + + atomic_set(&elliptic_data->abort_io, 0); + elliptic_data_reset_debug_counters(elliptic_data); + + EL_PRINT_I("Opened device elliptic%u", minor); + dev->opened = 1; + return 0; +} + + +int elliptic_data_initialize(struct elliptic_data + *elliptic_data, size_t queue_size, + unsigned int wakeup_timeout, int id) +{ + int is_power_of_two; + + is_power_of_two = (queue_size != 0) && !(queue_size & (queue_size - 1)); + + if (is_power_of_two != 1) { + EL_PRINT_E("non power of 2 fifo size"); + return -EINVAL; + } + + if (kfifo_alloc(&elliptic_data->fifo_isr, + queue_size, GFP_KERNEL) != 0) { + EL_PRINT_E("failed to allocate fifo isr"); + return -EINVAL; + } + + atomic_set(&elliptic_data->abort_io, 0); + spin_lock_init(&elliptic_data->fifo_isr_spinlock); + + elliptic_data->wakeup_timeout = wakeup_timeout; + + mutex_init(&elliptic_data->user_buffer_lock); + init_waitqueue_head(&elliptic_data->fifo_isr_not_empty); + + return 0; +} + +int elliptic_data_cleanup(struct elliptic_data *elliptic_data) +{ + spin_unlock(&elliptic_data->fifo_isr_spinlock); + kfifo_free(&elliptic_data->fifo_isr); + return 0; +} + +size_t elliptic_data_pop(struct elliptic_data + *elliptic_data, char __user *user_buffer, size_t buffer_size) +{ + int result; + unsigned long num_copied; + unsigned int fifo_result; + unsigned long flags; + + if (buffer_size < ELLIPTIC_MSG_BUF_SIZE) { + EL_PRINT_E("buffer_size : %lu smaller than %lu", + buffer_size, (size_t)ELLIPTIC_MSG_BUF_SIZE); + return 0; + } + + result = wait_event_interruptible(elliptic_data->fifo_isr_not_empty, + (kfifo_is_empty(&elliptic_data->fifo_isr) == 0) + || (atomic_read(&elliptic_data->abort_io) == 1)); + + if (atomic_read(&elliptic_data->abort_io) == 1) { + atomic_set(&elliptic_data->abort_io, 0); + EL_PRINT_D("pop cancelled"); + return 0; + } + + if (result == 0) { + spin_lock_irqsave(&elliptic_data->fifo_isr_spinlock, flags); + + fifo_result = kfifo_out(&elliptic_data->fifo_isr, + elliptic_data->isr_swap_buffer, ELLIPTIC_MSG_BUF_SIZE); + + spin_unlock_irqrestore(&elliptic_data->fifo_isr_spinlock, + flags); + + if (fifo_result == 0) { + EL_PRINT_E("failed to copy: fifo isr -> swap buffer %u", + fifo_result); + return 0; + } + + mutex_lock(&elliptic_data->user_buffer_lock); + + num_copied = copy_to_user(user_buffer, + elliptic_data->isr_swap_buffer, + ELLIPTIC_MSG_BUF_SIZE); + + mutex_unlock(&elliptic_data->user_buffer_lock); + + if (num_copied != 0) { + EL_PRINT_E("failed copy to user"); + return 0; + } + ++elliptic_data->userspace_read_total; + } else { + if (-ERESTARTSYS == result) + EL_PRINT_I("wait interrupted"); + else + EL_PRINT_E("wait error = %d", result); + + return 0; + } + + return (size_t)ELLIPTIC_MSG_BUF_SIZE; +} + + + +/* push data to specific device or all devices */ +int elliptic_data_push(int deviceid, + const char *buffer, + size_t buffer_size, + elliptic_data_push_t data_source) +{ + size_t available_space; + size_t space_required; + size_t zeros_to_pad; + unsigned int copied_from_user; + int copy_from_user_result; + int err; + int i; + int i_max; + + unsigned long flags; + struct elliptic_device *device; + struct elliptic_data *elliptic_data; + unsigned int fifo_result; + static uint8_t zero_pad_buffer[ELLIPTIC_MSG_BUF_SIZE]; + + err = 0; + fifo_result = 0; + copied_from_user = 0; + copy_from_user_result = 0; + if (buffer_size > ELLIPTIC_MSG_BUF_SIZE) + return -EINVAL; + + zeros_to_pad = ELLIPTIC_MSG_BUF_SIZE - buffer_size; + + i = 0; + i_max = ELLIPTIC_NUM_DEVICES; + + if (deviceid != ELLIPTIC_ALL_DEVICES) { + /* Copy to specific device */ + i = deviceid; + i_max = i + 1; + } + + for (; i < i_max; ++i) { + device = &elliptic_devices[i]; + elliptic_data = &device->el_data; + + if ((!device->opened)) + continue; + + available_space = kfifo_avail(&elliptic_data->fifo_isr); + space_required = ELLIPTIC_MSG_BUF_SIZE; + + spin_lock_irqsave(&elliptic_data->fifo_isr_spinlock, flags); + + if (available_space < space_required) { + + ++elliptic_data->isr_fifo_discard; + elliptic_data_isr_fifo_pop(elliptic_data, + ELLIPTIC_MSG_BUF_SIZE); + } + + if (data_source == ELLIPTIC_DATA_PUSH_FROM_KERNEL) { + fifo_result = kfifo_in(&elliptic_data->fifo_isr, + buffer, buffer_size); + + if (fifo_result == 0) { + spin_unlock_irqrestore( + &elliptic_data->fifo_isr_spinlock, + flags); + continue; + } + } else if (data_source == ELLIPTIC_DATA_PUSH_FROM_USERSPACE) { + copy_from_user_result = kfifo_from_user( + &elliptic_data->fifo_isr, buffer, + buffer_size, &copied_from_user); + + if (-EFAULT == copy_from_user_result) { + spin_unlock_irqrestore( + &elliptic_data->fifo_isr_spinlock, + flags); + continue; + } + } + + + if (zeros_to_pad > 0) { + fifo_result = kfifo_in( + &elliptic_data->fifo_isr, zero_pad_buffer, + zeros_to_pad); + + if (fifo_result == 0) { + elliptic_data_isr_fifo_pop(elliptic_data, + buffer_size); + + spin_unlock_irqrestore( + &elliptic_data->fifo_isr_spinlock, + flags); + + ++elliptic_data->isr_fifo_discard; + continue; + } + } + + + ++elliptic_data->isr_write_total; + spin_unlock_irqrestore( + &elliptic_data->fifo_isr_spinlock, flags); + wake_up_interruptible(&elliptic_data->fifo_isr_not_empty); + __pm_wakeup_event(wake_source, elliptic_data->wakeup_timeout); + } + + return err; +} + +int elliptic_open_port(int portid) +{ + return elliptic_io_open_port(portid); +} + +int elliptic_close_port(int portid) +{ + return elliptic_io_close_port(portid); +} + + +int32_t elliptic_data_write(uint32_t message_id, + const char *data, size_t data_size) +{ + int32_t err_dsp; + /* int32_t err_us; */ + + err_dsp = 0; + err_dsp = elliptic_data_io_write(message_id, data, data_size); + if (err_dsp) + EL_PRINT_E("Failed write to DSP"); + return err_dsp; + + /* + * err_us = 0; + * err_us = elliptic_userspace_ctrl_write(message_id, data, data_size); + * if(err_us){ + * EL_PRINT_E("Failed write to user space"); + *} + * + *return (err_dsp | err_us); + */ +} + + + +/** +* +* @return Number of bytes read. +*/ +static ssize_t device_read(struct file *fp, char __user *buff, + size_t length, loff_t *ppos) +{ + ssize_t bytes_read = 0; + struct elliptic_device *elliptic_device; + struct elliptic_data *elliptic_data; + + elliptic_device = (struct elliptic_device *)fp->private_data; + elliptic_data = (struct elliptic_data *)&elliptic_device->el_data; + + bytes_read = elliptic_data_pop(elliptic_data, buff, length); + + return bytes_read; +} + +/** +* +* @return number of bytes actually written +*/ +static ssize_t device_write(struct file *fp, const char *buff, + size_t length, loff_t *ppos) +{ + ssize_t ret_val; + + ret_val = 0; + if ((buff != NULL) && (length != 0)) + ret_val = elliptic_data_io_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + buff, length); + + return ret_val >= 0 ? (ssize_t)length : 0; +} + + +static long device_ioctl(struct file *fp, unsigned int number, + unsigned long param) +{ + struct elliptic_device *device; + struct elliptic_data *elliptic_data; + int err; + unsigned int mirror_tag, mirror_payload_size; + unsigned char *data_ptr; + + device = (struct elliptic_device *)(fp->private_data); + elliptic_data = &device->el_data; + + switch (number) { + case IOCTL_ELLIPTIC_DATA_IO_CANCEL: + EL_PRINT_D("IOCTL_ELLIPTIC_CANCEL_READ %ld", + param); + elliptic_data_cancel(elliptic_data); + break; + + case IOCTL_ELLIPTIC_DATA_IO_MIRROR: + data_ptr = (unsigned char *)param; + mirror_tag = *(unsigned int *)data_ptr; + mirror_payload_size = *((unsigned int *)data_ptr + 1); + + if ((mirror_tag == MIRROR_TAG) && + (mirror_payload_size != 0) && + (mirror_payload_size <= + (ELLIPTIC_SET_PARAMS_SIZE * 4))) { + + err = elliptic_data_io_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (data_ptr + 8), mirror_payload_size); + + if (err != 0) { + EL_PRINT_E("elliptic_data_io_write failed"); + return err; + } + + } else { + EL_PRINT_E("TAG or Length is not valid"); + } + + break; + + default: + EL_PRINT_W("UNKNOWN IOCTL number=%d", number); + break; + } + + return 0; +} + + +static unsigned int device_poll(struct file *file, + struct poll_table_struct *poll_table) +{ + unsigned int mask; + + struct elliptic_device *device; + struct elliptic_data *elliptic_data; + + mask = 0; + device = (struct elliptic_device *)file->private_data; + elliptic_data = (struct elliptic_data *)&device->el_data; + + poll_wait(file, &elliptic_data->fifo_isr_not_empty, poll_table); + + if (!kfifo_is_empty(&elliptic_data->fifo_isr)) + mask = POLLIN | POLLRDNORM; + + return mask; +} + + +static int device_close(struct inode *inode, struct file *filp) +{ + struct elliptic_device *device; + struct elliptic_data *elliptic_data; + unsigned int minor; + + device = filp->private_data; + elliptic_data = &device->el_data; + minor = iminor(inode); + if (device == NULL) { + EL_PRINT_E("device not found"); + return -ENODEV; + } + + device->opened = 0; + elliptic_data_update_debug_counters(elliptic_data); + elliptic_data_print_debug_counters(elliptic_data); + elliptic_data_cancel(elliptic_data); + up(&device->sem); + + EL_PRINT_I("Closed device elliptic%u", minor); + return 0; +} + +/* defines the file operations provided by the driver */ +static const struct file_operations elliptic_fops = { + .owner = THIS_MODULE, /* prevents unloading when operations are in use*/ + .open = device_open, /*to open the device*/ + .write = device_write, /*to write to the device*/ + .read = device_read, /*to read the device*/ + .poll = device_poll, + .unlocked_ioctl = device_ioctl, /* IOCTL calls */ + .release = device_close, /*to close the device*/ +}; + + +static int elliptic_device_initialize(struct elliptic_device + *elliptic_device, int minor, struct class *class) +{ + int err; + dev_t device_number; + struct device *device; + + BUG_ON(elliptic_device == NULL || class == NULL); + + err = 0; + device = NULL; + device_number = MKDEV(elliptic_major, minor); + /* Memory is to be allocated when the device is opened the first time */ + sema_init(&elliptic_device->sem, 1); + cdev_init(&elliptic_device->cdev, &elliptic_fops); + elliptic_device->cdev.owner = THIS_MODULE; + + err = cdev_add(&elliptic_device->cdev, device_number, 1); + + if (err) { + EL_PRINT_E("error %d while trying to add %s%d", + err, ELLIPTIC_DEVICENAME, minor); + return err; + } + + device = device_create(class, NULL, device_number, + NULL, ELLIPTIC_DEVICENAME "%d", minor); + + if (IS_ERR(device)) { + err = PTR_ERR(device); + EL_PRINT_E("error %d while trying to create %s%d", + err, ELLIPTIC_DEVICENAME, minor); + cdev_del(&elliptic_device->cdev); + return err; + } + + if (err) { + EL_PRINT_E("failed device initialize"); + return err; + } + + return 0; +} + +static void elliptic_device_cleanup(struct elliptic_device *dev, int minor, + struct class *class) + +{ + BUG_ON(dev == NULL || class == NULL); + device_destroy(class, MKDEV(elliptic_major, minor)); + cdev_del(&dev->cdev); + up(&dev->sem); +} + +static void elliptic_driver_cleanup(int devices_to_destroy) +{ + int i; + + if (elliptic_devices) { + elliptic_data_io_cleanup(); + + for (i = 0; i < devices_to_destroy; ++i) { + elliptic_data_cleanup(&elliptic_devices[i].el_data); + elliptic_device_cleanup( + &elliptic_devices[i], i, elliptic_class); + } + + kfree(elliptic_devices); + } + + if (elliptic_class) + class_destroy(elliptic_class); + + unregister_chrdev_region( + MKDEV(elliptic_major, 0), ELLIPTIC_NUM_DEVICES); +} + + + +#ifdef ELLIPTIC_LOAD_CALIBRATION_DATA_FROM_FILESYSTEM + +#define ELLIPTIC_CALIBRATION_MAX_DATA_SIZE (ELLIPTIC_CALIBRATION_V2_DATA_SIZE + ELLIPTIC_CALIBRATION_DATA_SIZE) +static unsigned char calibration_data[ELLIPTIC_CALIBRATION_MAX_DATA_SIZE]; +static char *calibration_filename = "/persist/audio/elliptic_calibration"; + +/* function to load the calibration from a file (if possible) */ +static size_t load_calibration_data(char *filename) +{ + size_t ret = 0; + int fd; + + mm_segment_t old_fs = get_fs(); + + set_fs(KERNEL_DS); + + fd = sys_open(filename, O_RDONLY, 0); + if (fd >= 0) { + size_t bytes_read = sys_read(fd, calibration_data, ELLIPTIC_CALIBRATION_MAX_DATA_SIZE); + + if (bytes_read == ELLIPTIC_CALIBRATION_DATA_SIZE || + bytes_read == ELLIPTIC_CALIBRATION_V2_DATA_SIZE) { + ret = bytes_read; + } + sys_close(fd); + } + set_fs(old_fs); + return ret; +} + +static int32_t elliptic_send_calibration_to_engine(size_t calib_data_size) +{ + elliptic_set_calibration_data(calibration_data, calib_data_size); + return elliptic_data_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)calibration_data, calib_data_size); +} + +#endif + + +int __init elliptic_driver_init(void) +{ + int err; + int i; + int devices_to_destroy; + dev_t device_number; + + err = alloc_chrdev_region(&device_number, 0, ELLIPTIC_NUM_DEVICES, + ELLIPTIC_DEVICENAME); + + devices_to_destroy = 0; + + if (err < 0) { + EL_PRINT_E("Failed to allocate cdev region"); + return err; + } + + elliptic_major = MAJOR(device_number); + elliptic_class = class_create(THIS_MODULE, "chardev"); + + if (elliptic_class == NULL) { + EL_PRINT_E("Class creation failed"); + goto fail; + } + + err = elliptic_initialize_sysfs(); + + if (err) + goto fail; + + elliptic_devices = (struct elliptic_device *) + kzalloc(sizeof(struct elliptic_device) * ELLIPTIC_NUM_DEVICES, + GFP_KERNEL); + + if (elliptic_devices == NULL) { + err = -ENOMEM; + goto fail; + } + + + for (i = 0; i < ELLIPTIC_NUM_DEVICES; ++i) { + if (elliptic_device_initialize(&elliptic_devices[i], i, + elliptic_class)) { + devices_to_destroy = i; + goto fail; + } + + if (elliptic_data_initialize(&elliptic_devices[i].el_data, + ELLIPTIC_DATA_FIFO_SIZE, ELLIPTIC_WAKEUP_TIMEOUT, i)) { + goto fail; + } + } + + if (elliptic_data_io_initialize()) + goto fail; + + if (elliptic_userspace_io_driver_init()) + goto fail; + + + if (elliptic_userspace_ctrl_driver_init()) + goto fail; + + wake_source = kmalloc(sizeof(struct wakeup_source), GFP_KERNEL); + + if (!wake_source) { + EL_PRINT_E("failed to allocate wake source"); + return -ENOMEM; + } + + wakeup_source_init(wake_source, "elliptic_wake_source"); + +#ifdef ELLIPTIC_LOAD_CALIBRATION_DATA_FROM_FILESYSTEM + /* Code to send calibration to engine */ + { + size_t calib_data_size = load_calibration_data(calibration_filename); + if (calib_data_size > 0) + elliptic_send_calibration_to_engine(calib_data_size); + } +#endif + return 0; + +fail: + elliptic_driver_cleanup(devices_to_destroy); + return err; +} + +void elliptic_driver_exit(void) +{ + if (wake_source) { + wakeup_source_trash(wake_source); + kfree(wake_source); + } + + elliptic_cleanup_sysfs(); + elliptic_driver_cleanup(ELLIPTIC_NUM_DEVICES); + elliptic_userspace_io_driver_exit(); + elliptic_userspace_ctrl_driver_exit(); +} + +MODULE_AUTHOR("Elliptic Labs"); +MODULE_DESCRIPTION("Providing Interface to UPS data"); +MODULE_LICENSE("GPL"); diff --git a/techpack/audio/dsp/elliptic/elliptic_mixer_controls.c b/techpack/audio/dsp/elliptic/elliptic_mixer_controls.c new file mode 100755 index 000000000000..5b4afd2b0560 --- /dev/null +++ b/techpack/audio/dsp/elliptic/elliptic_mixer_controls.c @@ -0,0 +1,1339 @@ +/** + * Elliptic Labs + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +struct elliptic_system_configuration { + union { + uint8_t reserved[ELLIPTIC_SYSTEM_CONFIGURATION_SIZE]; + }; +}; + +struct elliptic_system_configuration elliptic_system_configuration; + + +struct elliptic_system_configuration_parameter { + enum elliptic_system_configuration_parameter_type type; + union { + int32_t speaker_scaling[2]; + int32_t sensitivity; + int32_t latency; + int32_t microphone_index; + int32_t operation_mode; + int32_t operation_mode_flags; + int32_t component_gain_change; + int32_t calibration_state; + int32_t engine_version; + int32_t calibration_profile; + int32_t ultrasound_gain; + int32_t log_level; + int32_t custom_setting; + int32_t engine_suspend; + int32_t input_enabled; + int32_t output_enabled; + int32_t external_event; + struct { + int32_t calibration_method; + int32_t calibration_timestamp; + }; + int32_t debug_mode; + int32_t context; + int32_t capture; + int32_t input_channels; + }; +}; + +struct elliptic_system_configuration_parameters_cache + elliptic_system_configuration_cache = { {0}, 0 }; + +static struct elliptic_engine_version_info + elliptic_engine_version_cache = { 0xde, 0xad, 0xbe, 0xef }; + +struct elliptic_engine_calibration_data { + union { + uint8_t reserved[ELLIPTIC_CALIBRATION_DATA_SIZE]; + }; +}; + +static struct elliptic_engine_calibration_data + elliptic_engine_calibration_data_cache = { .reserved = { + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } }; + +struct elliptic_engine_calibration_v2_data { + union { + uint8_t reserved[ELLIPTIC_CALIBRATION_V2_DATA_SIZE]; + }; +}; + +static struct elliptic_engine_calibration_v2_data + elliptic_engine_calibration_v2_data_cache = { .reserved = { + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, + +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, +0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, +0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, +0xef, 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef, +} }; + +struct elliptic_engine_diagnostics_data { + union { + uint8_t reserved[ELLIPTIC_DIAGNOSTICS_DATA_SIZE]; + uint32_t values32[ELLIPTIC_DIAGNOSTICS_DATA_SIZE >> 2]; + }; +}; + +static struct elliptic_engine_diagnostics_data + elliptic_engine_diagnostics_data_cache = { .reserved = {0} }; + +struct elliptic_engine_ml_data { + union { + uint8_t reserved[ELLIPTIC_ML_DATA_SIZE]; + uint32_t u32[ELLIPTIC_ML_DATA_SIZE >> 2]; + }; +}; + +static struct elliptic_engine_ml_data + elliptic_engine_ml_data_cache + = { .reserved = {0} }; + +struct elliptic_engine_sensor_data { + union { + uint8_t reserved[ELLIPTIC_SENSOR_DATA_SIZE]; + uint32_t values32[ELLIPTIC_SENSOR_DATA_SIZE >> 2]; + }; +}; + +static struct elliptic_engine_sensor_data + elliptic_engine_sensor_data_cache = { .reserved = {0} }; + +struct elliptic_engine_branch_info { + char build_branch[ELLIPTIC_BRANCH_INFO_MAX_SIZE]; +}; + +static struct elliptic_engine_branch_info + elliptic_engine_branch_cache = { { 0 } }; + +struct elliptic_engine_tag_info { + char engine_tag[ELLIPTIC_TAG_INFO_SIZE]; +}; + +static struct elliptic_engine_tag_info + elliptic_engine_tag_cache = { { 0 } }; + +static struct elliptic_shared_data_block shared_data_blocks[] = { + { ELLIPTIC_OBJ_ID_CALIBRATION_DATA, ELLIPTIC_CALIBRATION_DATA_SIZE, + &elliptic_engine_calibration_data_cache }, + + { ELLIPTIC_OBJ_ID_VERSION_INFO, ELLIPTIC_VERSION_INFO_SIZE, + &elliptic_engine_version_cache }, + { ELLIPTIC_OBJ_ID_BRANCH_INFO, ELLIPTIC_BRANCH_INFO_MAX_SIZE, + &elliptic_engine_branch_cache }, + { ELLIPTIC_OBJ_ID_CALIBRATION_V2_DATA, + ELLIPTIC_CALIBRATION_V2_DATA_SIZE, + &elliptic_engine_calibration_v2_data_cache }, + { ELLIPTIC_OBJ_ID_DIAGNOSTICS_DATA, ELLIPTIC_DIAGNOSTICS_DATA_SIZE, + &elliptic_engine_diagnostics_data_cache }, + { ELLIPTIC_OBJ_ID_TAG_INFO, ELLIPTIC_TAG_INFO_SIZE, + &elliptic_engine_tag_cache }, + { ELLIPTIC_OBJ_ID_ML_DATA, + ELLIPTIC_ML_DATA_SIZE, + &elliptic_engine_ml_data_cache }, +}; + +void elliptic_set_calibration_data(uint8_t *calib_data, size_t size) +{ + struct elliptic_shared_data_block *calibration_obj = NULL; + + if (size == ELLIPTIC_CALIBRATION_DATA_SIZE) { + calibration_obj = elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_CALIBRATION_DATA); + memcpy((uint8_t *)&elliptic_engine_calibration_data_cache, + calib_data, size); + } + if (size == ELLIPTIC_CALIBRATION_V2_DATA_SIZE) { + calibration_obj = elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_CALIBRATION_V2_DATA); + memcpy((uint8_t *)&elliptic_engine_calibration_v2_data_cache, + calib_data, size); + } + if (calibration_obj == NULL) { + EL_PRINT_E( + "ell..set_calibration_data() calib=NULL (%zu)", size); + return; + } + memcpy((u8 *)calibration_obj->buffer, calib_data, size); +} + +void elliptic_set_diagnostics_data(uint8_t *diag_data, size_t size) +{ + struct elliptic_shared_data_block *diagnostics_obj = NULL; + + if (size <= ELLIPTIC_DIAGNOSTICS_DATA_SIZE) { + diagnostics_obj = + elliptic_get_shared_obj( + ELLIPTIC_OBJ_ID_DIAGNOSTICS_DATA); + if (diagnostics_obj == NULL) { + EL_PRINT_E("el..set_diagnostics_data() NULL (%zu)", + size); + return; + } + memcpy((uint8_t *)&elliptic_engine_diagnostics_data_cache, + diag_data, size); + memcpy((u8 *)diagnostics_obj->buffer, diag_data, size); + } +} + +static const size_t NUM_SHARED_RW_OBJS = + sizeof(shared_data_blocks) / sizeof(struct elliptic_shared_data_block); + +struct elliptic_shared_data_block *elliptic_get_shared_obj(uint32_t + object_id) { + + size_t i; + + for (i = 0; i < NUM_SHARED_RW_OBJS; ++i) { + if (shared_data_blocks[i].object_id == object_id) + return &shared_data_blocks[i]; + } + + return NULL; +} + + +static const char * const ultrasound_enable_texts[] = {"Off", "On"}; + +static const struct soc_enum elliptic_enum[] = { + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ultrasound_enable_texts), + ultrasound_enable_texts), +}; + +int get_elliptic_calibration_data(uint8_t *caldata, uint32_t max_size) +{ + uint32_t copied; + + copied = ELLIPTIC_CALIBRATION_DATA_SIZE; + if (max_size < ELLIPTIC_CALIBRATION_DATA_SIZE) { + copied = max_size; + EL_PRINT_D("size mismatch : %u vs %u", + (uint32_t)ELLIPTIC_CALIBRATION_DATA_SIZE, max_size); + } + + memcpy(caldata, (uint8_t *)&elliptic_engine_calibration_data_cache, + max_size); + return copied; +} + +int get_elliptic_calibration_v2_data(uint8_t *caldata, uint32_t max_size) +{ + uint32_t copied; + + copied = ELLIPTIC_CALIBRATION_V2_DATA_SIZE; + if (max_size < ELLIPTIC_CALIBRATION_V2_DATA_SIZE) { + copied = max_size; + EL_PRINT_D("size mismatch : %u vs %u", + (uint32_t)ELLIPTIC_CALIBRATION_V2_DATA_SIZE, max_size); + } + + memcpy(caldata, (uint8_t *)&elliptic_engine_calibration_v2_data_cache, + max_size); + return copied; +} + +int get_elliptic_diagnostics_data(uint8_t *diagdata, uint32_t max_size) +{ + uint32_t copied; + + copied = ELLIPTIC_DIAGNOSTICS_DATA_SIZE; + if (max_size < ELLIPTIC_DIAGNOSTICS_DATA_SIZE) { + copied = max_size; + EL_PRINT_D("size mismatch : %u vs %u", + (uint32_t)ELLIPTIC_DIAGNOSTICS_DATA_SIZE, max_size); + } + + memcpy(diagdata, (uint8_t *)&elliptic_engine_diagnostics_data_cache, + max_size); + return copied; +} + + +static uint32_t ultrasound_enable_cache; + +int elliptic_ultrasound_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = ultrasound_enable_cache; + return 0; +} + +int elliptic_ultrasound_enable_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + static bool triggered_engine_info; + int32_t msg[4] = {0, 0, 0, 0}; + + ultrasound_enable_cache = ucontrol->value.integer.value[0]; + + if (!triggered_engine_info && ultrasound_enable_cache) { + triggered_engine_info = true; + elliptic_trigger_version_msg(); + elliptic_trigger_branch_msg(); + elliptic_trigger_tag_msg(); + } + + msg[0] = ultrasound_enable_cache ? 1 : 0; + + return elliptic_data_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} + +static uint32_t ultrasound_tx_port_cache; + +int elliptic_ultrasound_tx_port_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = ultrasound_tx_port_cache; + return 0; +} + +int elliptic_ultrasound_tx_port_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + + if (ultrasound_tx_port_cache == ucontrol->value.integer.value[0]) { + EL_PRINT_E("ultrasound_tx_port_set: ignoring duplicate request"); + return 0; + } + + ultrasound_tx_port_cache = ucontrol->value.integer.value[0]; + if (ultrasound_tx_port_cache) + ret = elliptic_open_port(ULTRASOUND_TX_PORT_ID); + else + ret = elliptic_close_port(ULTRASOUND_TX_PORT_ID); + + EL_PRINT_E("ultrasound_tx_port: enable=%d ret=%d", + ultrasound_tx_port_cache, ret); + + return ret; +} + +static uint32_t ultrasound_rx_port_cache; + +int elliptic_ultrasound_rx_port_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = ultrasound_rx_port_cache; + return 0; +} + +int elliptic_ultrasound_rx_port_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int ret; + + if (ultrasound_rx_port_cache == ucontrol->value.integer.value[0]) { + EL_PRINT_E("ultrasound_rx_port_set: ignoring duplicate request"); + return 0; + } + + ultrasound_rx_port_cache = ucontrol->value.integer.value[0]; + if (ultrasound_rx_port_cache) + ret = elliptic_open_port(ULTRASOUND_RX_PORT_ID); + else + ret = elliptic_close_port(ULTRASOUND_RX_PORT_ID); + + EL_PRINT_E("ultrasound_rx_port: enable=%d ret=%d", + ultrasound_tx_port_cache, ret); + + return 0; +} + +int elliptic_ultrasound_rampdown_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* Rampdown is a strobe, so always return Off */ + ucontrol->value.integer.value[0] = 0; + return 0; +} + +int elliptic_ultrasound_rampdown_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int32_t msg[4] = {-1, 0, 0, 0}; + + if (ucontrol->value.integer.value[0] == 0) + return 0; + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} + +int elliptic_ultrasound_diagnostics_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + /* Diagnostics is a strobe, so always return Off */ + ucontrol->value.integer.value[0] = 0; + return 0; +} + +int elliptic_ultrasound_request_diagnostics(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int32_t msg[3] = {ESCPT_ENGINE_DIAGNOSTICS, 0, 0}; + + if (ucontrol->value.integer.value[0] == 0) + return 0; + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} + +int elliptic_system_configuration_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(ucontrol->value.bytes.data, &elliptic_system_configuration, + ELLIPTIC_SYSTEM_CONFIGURATION_SIZE); + return 0; +} + +int elliptic_system_configuration_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(&elliptic_system_configuration, ucontrol->value.bytes.data, + ELLIPTIC_SYSTEM_CONFIGURATION_SIZE); + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)&elliptic_system_configuration, + ELLIPTIC_SYSTEM_CONFIGURATION_SIZE); +} + +int elliptic_calibration_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(ucontrol->value.bytes.data, + &elliptic_engine_calibration_data_cache, + ELLIPTIC_CALIBRATION_DATA_SIZE); + return 0; +} + +int elliptic_calibration_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(&elliptic_engine_calibration_data_cache, + ucontrol->value.bytes.data, ELLIPTIC_CALIBRATION_DATA_SIZE); + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)&elliptic_engine_calibration_data_cache, + ELLIPTIC_CALIBRATION_DATA_SIZE); +} + +int elliptic_calibration_v2_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct elliptic_shared_data_block *calibration_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_CALIBRATION_V2_DATA); + + if (calibration_obj == NULL) { + EL_PRINT_E("calibration_obj is NULL"); + return -EINVAL; + } + + memcpy(ucontrol->value.bytes.data, + calibration_obj->buffer, + ELLIPTIC_CALIBRATION_V2_DATA_SIZE); + return 0; +} + +int elliptic_calibration_v2_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(&elliptic_engine_calibration_v2_data_cache, + ucontrol->value.bytes.data, ELLIPTIC_CALIBRATION_V2_DATA_SIZE); + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)&elliptic_engine_calibration_v2_data_cache, + ELLIPTIC_CALIBRATION_V2_DATA_SIZE); +} + +int elliptic_diagnostics_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(ucontrol->value.bytes.data, + &elliptic_engine_diagnostics_data_cache, + ELLIPTIC_DIAGNOSTICS_DATA_SIZE); + return 0; +} + +int elliptic_diagnostics_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +int elliptic_ml_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct elliptic_shared_data_block *ml_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_ML_DATA); + + if (ml_obj == NULL) { + EL_PRINT_E("ml_obj is NULL"); + return -EINVAL; + } + + memcpy(ucontrol->value.bytes.data, + ml_obj->buffer, + ELLIPTIC_ML_DATA_SIZE); + return 0; +} + +int elliptic_ml_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)ucontrol->value.bytes.data, + ELLIPTIC_ML_DATA_SIZE); +} + +int elliptic_sensor_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(ucontrol->value.bytes.data, + &elliptic_engine_sensor_data_cache, + ELLIPTIC_SENSOR_DATA_SIZE); + return 0; +} + +int elliptic_sensor_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(&elliptic_engine_sensor_data_cache, + ucontrol->value.bytes.data, ELLIPTIC_SENSOR_DATA_SIZE); + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)&elliptic_engine_sensor_data_cache, + ELLIPTIC_SENSOR_DATA_SIZE); +} + +int elliptic_version_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(ucontrol->value.bytes.data, &elliptic_engine_version_cache, + ELLIPTIC_VERSION_INFO_SIZE); + return 0; +} + +int elliptic_version_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +int elliptic_branch_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(ucontrol->value.bytes.data, &elliptic_engine_branch_cache, + ELLIPTIC_BRANCH_INFO_MAX_SIZE); + return 0; +} + +int elliptic_branch_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +int elliptic_tag_data_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memcpy(ucontrol->value.bytes.data, &elliptic_engine_tag_cache, + ELLIPTIC_TAG_INFO_SIZE); + return 0; +} + +int elliptic_tag_data_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +int elliptic_calibration_param_get( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + if (mc->reg != ELLIPTIC_CALIBRATION) + return -EINVAL; + + switch (mc->shift) { + case ELLIPTIC_CALIBRATION_STATE: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.calibration_state; + break; + + case ELLIPTIC_CALIBRATION_PROFILE: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.calibration_profile; + break; + + case ELLIPTIC_ULTRASOUND_GAIN: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.ultrasound_gain; + break; + + default: + return -EINVAL; + } + + return 1; +} + +int elliptic_calibration_param_put( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct elliptic_system_configuration_parameter param; + + if (mc->reg != ELLIPTIC_CALIBRATION) + return -EINVAL; + + switch (mc->shift) { + case ELLIPTIC_CALIBRATION_STATE: + elliptic_system_configuration_cache.calibration_state = + ucontrol->value.integer.value[0]; + + param.type = ESCPT_CALIBRATION_STATE; + param.calibration_state = + elliptic_system_configuration_cache.calibration_state; + break; + + case ELLIPTIC_CALIBRATION_PROFILE: + elliptic_system_configuration_cache.calibration_profile = + ucontrol->value.integer.value[0]; + + param.type = ESCPT_CALIBRATION_PROFILE; + param.calibration_profile = + elliptic_system_configuration_cache.calibration_profile; + break; + + case ELLIPTIC_ULTRASOUND_GAIN: + elliptic_system_configuration_cache.ultrasound_gain = + ucontrol->value.integer.value[0]; + param.type = ESCPT_ULTRASOUND_GAIN; + param.ultrasound_gain = + elliptic_system_configuration_cache.ultrasound_gain; + break; + + default: + return -EINVAL; + } + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (u8 *)¶m, sizeof(param)); +} + +int elliptic_system_configuration_param_get( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + + pr_err("%s: reg: %d shift: %d\n", __func__, mc->reg, mc->shift); + + if (mc->reg != ELLIPTIC_SYSTEM_CONFIGURATION) + return -EINVAL; + + if (mc->shift >= ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_0 && + mc->shift <= ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_15){ + EL_PRINT_E("get ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_%02d", + mc->shift - ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_0); + ucontrol->value.integer.value[0] = 0; + return 1; + } + + switch (mc->shift) { + case ELLIPTIC_SYSTEM_CONFIGURATION_LATENCY: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.latency; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_SENSITIVITY: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.sensitivity; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_SPEAKER_SCALING: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.speaker_scaling[0]; + ucontrol->value.integer.value[1] = + elliptic_system_configuration_cache.speaker_scaling[1]; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_MICROPHONE_INDEX: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.microphone_index; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.operation_mode; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE_FLAGS: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.operation_mode_flags; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_LOG_LEVEL: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.log_level; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_SUSPEND: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.engine_suspend; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_ENABLED: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.input_enabled; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_OUTPUT_ENABLED: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.output_enabled; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_EXTERNAL_EVENT: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.external_event; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_CALIBRATION_METHOD: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.calibration_method; + case ELLIPTIC_SYSTEM_CONFIGURATION_DEBUG_MODE: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.debug_mode; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_CONTEXT: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.context; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_CAPTURE: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.capture; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_CHANNELS: + ucontrol->value.integer.value[0] = + elliptic_system_configuration_cache.input_channels; + break; + + default: + EL_PRINT_E("Invalid mixer control"); + return -EINVAL; + } + + return 1; +} + + + +int elliptic_system_configuration_param_put( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_mixer_control *mc = + (struct soc_mixer_control *)kcontrol->private_value; + struct elliptic_system_configuration_parameter param; + struct timeval tv; + + if (mc->reg != ELLIPTIC_SYSTEM_CONFIGURATION) + return -EINVAL; + + if (mc->shift >= ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_0 && + mc->shift <= ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_15){ + const size_t csi = + mc->shift - + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_0; + EL_PRINT_E("ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_XX csi:%zu", csi); + if (csi >= + ARRAY_SIZE(elliptic_system_configuration_cache.custom_settings)) + return -EINVAL; + EL_PRINT_E("ucontrol->value.integer.value[0]:%ld", ucontrol->value.integer.value[0]); + elliptic_system_configuration_cache.custom_settings[csi] = + ucontrol->value.integer.value[0]; + param.type = ESCPT_ENGINE_CUSTOM_SETTING_0 + csi; + param.custom_setting = ucontrol->value.integer.value[0]; + EL_PRINT_E("calling elliptic_data_write(custom_setting) csi:%zu", csi); + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)¶m, sizeof(param)); + } + + + switch (mc->shift) { + case ELLIPTIC_SYSTEM_CONFIGURATION_LATENCY: + elliptic_system_configuration_cache.latency = + ucontrol->value.integer.value[0]; + param.type = ESCPT_LATENCY; + param.latency = elliptic_system_configuration_cache.latency; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_SENSITIVITY: + elliptic_system_configuration_cache.sensitivity = + ucontrol->value.integer.value[0]; + param.type = ESCPT_CHANNEL_SENSITIVITY; + param.sensitivity = + elliptic_system_configuration_cache.sensitivity; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_SPEAKER_SCALING: + elliptic_system_configuration_cache.speaker_scaling[0] = + ucontrol->value.integer.value[0]; + elliptic_system_configuration_cache.speaker_scaling[1] = + ucontrol->value.integer.value[1]; + param.type = ESCPT_SPEAKER_SCALING; + param.speaker_scaling[0] = + elliptic_system_configuration_cache.speaker_scaling[0]; + param.speaker_scaling[1] = + elliptic_system_configuration_cache.speaker_scaling[1]; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_MICROPHONE_INDEX: + elliptic_system_configuration_cache.microphone_index = + ucontrol->value.integer.value[0]; + param.type = ESCPT_MICROPHONE_INDEX; + param.microphone_index = + elliptic_system_configuration_cache.microphone_index; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE: + elliptic_system_configuration_cache.operation_mode = + ucontrol->value.integer.value[0]; + param.type = ESCPT_OPERATION_MODE; + param.operation_mode = + elliptic_system_configuration_cache.operation_mode; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE_FLAGS: + elliptic_system_configuration_cache.operation_mode_flags = + ucontrol->value.integer.value[0]; + param.type = ESCPT_OPERATION_MODE_FLAGS; + param.operation_mode_flags = + elliptic_system_configuration_cache.operation_mode_flags; + break; + + case ELLIPTIC_SYSTEM_CONFIGURATION_LOG_LEVEL: + elliptic_system_configuration_cache.log_level = + ucontrol->value.integer.value[0]; + param.type = ESCPT_LOG_LEVEL; + param.log_level = + elliptic_system_configuration_cache.log_level; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_ENABLED: + elliptic_system_configuration_cache.input_enabled = + ucontrol->value.integer.value[0]; + param.type = ESCPT_INPUT_ENABLED; + param.input_enabled = + elliptic_system_configuration_cache.input_enabled; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_OUTPUT_ENABLED: + elliptic_system_configuration_cache.output_enabled = + ucontrol->value.integer.value[0]; + param.type = ESCPT_OUTPUT_ENABLED; + param.output_enabled = + elliptic_system_configuration_cache.output_enabled; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_SUSPEND: + elliptic_system_configuration_cache.engine_suspend = + ucontrol->value.integer.value[0]; + param.type = ESCPT_SUSPEND; + param.engine_suspend = + elliptic_system_configuration_cache.engine_suspend; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_EXTERNAL_EVENT: + elliptic_system_configuration_cache.external_event = + ucontrol->value.integer.value[0]; + param.type = ESCPT_EXTERNAL_EVENT; + param.external_event = + elliptic_system_configuration_cache.external_event; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_CALIBRATION_METHOD: + elliptic_system_configuration_cache.calibration_method = + ucontrol->value.integer.value[0]; + param.type = ESCPT_CALIBRATION_METHOD; + param.calibration_method = + elliptic_system_configuration_cache.calibration_method; + do_gettimeofday(&tv); + param.calibration_timestamp = (int32_t)tv.tv_sec; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_DEBUG_MODE: + elliptic_system_configuration_cache.debug_mode = + ucontrol->value.integer.value[0]; + param.type = ESCPT_DEBUG_MODE; + param.debug_mode = + elliptic_system_configuration_cache.debug_mode; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_CONTEXT: + elliptic_system_configuration_cache.context = + ucontrol->value.integer.value[0]; + param.type = ESCPT_CONTEXT; + param.context = + elliptic_system_configuration_cache.context; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_CAPTURE: + elliptic_system_configuration_cache.capture = + ucontrol->value.integer.value[0]; + param.type = ESCPT_CAPTURE; + param.context = + elliptic_system_configuration_cache.capture; + break; + case ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_CHANNELS: + elliptic_system_configuration_cache.input_channels = + ucontrol->value.integer.value[0]; + param.type = ESCPT_INPUT_CHANNELS; + param.context = + elliptic_system_configuration_cache.input_channels; + break; + + default: + return -EINVAL; + } + + return elliptic_data_write(ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)¶m, sizeof(param)); +} + + +static const struct snd_kcontrol_new ultrasound_filter_mixer_controls[] = { + SOC_ENUM_EXT("Ultrasound Enable", + elliptic_enum[0], + elliptic_ultrasound_enable_get, + elliptic_ultrasound_enable_set), + SOC_ENUM_EXT("Ultrasound RampDown", + elliptic_enum[0], + elliptic_ultrasound_rampdown_get, + elliptic_ultrasound_rampdown_set), + SOC_SINGLE_EXT("Ultrasound Latency", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_LATENCY, + 10000, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Sensitivity", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_SENSITIVITY, + 1000000, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_DOUBLE_EXT("Ultrasound Speaker Scaling", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_SPEAKER_SCALING, + 0, + 1000000, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Microphone Index", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_MICROPHONE_INDEX, + 20, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Mode", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE, + 255, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Mode Flags", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE_FLAGS, + 256, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Calibration Profile", + ELLIPTIC_CALIBRATION, + ELLIPTIC_CALIBRATION_PROFILE, + 256, + 0, + elliptic_calibration_param_get, + elliptic_calibration_param_put), + SOC_SINGLE_EXT("Ultrasound Gain", + ELLIPTIC_CALIBRATION, + ELLIPTIC_ULTRASOUND_GAIN, + 256, + 0, + elliptic_calibration_param_get, + elliptic_calibration_param_put), + + SOC_SINGLE_EXT("Ultrasound Calibration State", + ELLIPTIC_CALIBRATION, + ELLIPTIC_CALIBRATION_STATE, + 256, + 0, + elliptic_calibration_param_get, + elliptic_calibration_param_put), + + SND_SOC_BYTES_EXT("Ultrasound System Configuration", + ELLIPTIC_SYSTEM_CONFIGURATION_SIZE, + elliptic_system_configuration_get, + elliptic_system_configuration_put), + SND_SOC_BYTES_EXT("Ultrasound Calibration Data", + ELLIPTIC_CALIBRATION_DATA_SIZE, + elliptic_calibration_data_get, + elliptic_calibration_data_put), + SND_SOC_BYTES_EXT("Ultrasound Version", + ELLIPTIC_VERSION_INFO_SIZE, + elliptic_version_data_get, + elliptic_version_data_put), + SND_SOC_BYTES_EXT("Ultrasound Branch", + ELLIPTIC_BRANCH_INFO_MAX_SIZE, + elliptic_branch_data_get, + elliptic_branch_data_put), + SND_SOC_BYTES_EXT("Ultrasound Tag", + ELLIPTIC_TAG_INFO_SIZE, + elliptic_tag_data_get, + elliptic_tag_data_put), + SOC_SINGLE_EXT("Ultrasound Log Level", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_LOG_LEVEL, + 7, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + + SND_SOC_BYTES_EXT("Ultrasound Calibration Ext Data", + ELLIPTIC_CALIBRATION_V2_DATA_SIZE, + elliptic_calibration_v2_data_get, + elliptic_calibration_v2_data_put), + + SND_SOC_BYTES_EXT("Ultrasound Diagnostics Data", + ELLIPTIC_DIAGNOSTICS_DATA_SIZE, + elliptic_diagnostics_data_get, + elliptic_diagnostics_data_put), + + SOC_ENUM_EXT("Ultrasound Diagnostics Request", + elliptic_enum[0], + elliptic_ultrasound_diagnostics_get, + elliptic_ultrasound_request_diagnostics), + + SOC_SINGLE_EXT("Ultrasound Custom Setting 0", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_0, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 1", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_1, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 2", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_2, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 3", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_3, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 4", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_4, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 5", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_5, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 6", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_6, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 7", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_7, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 8", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_8, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 9", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_9, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 10", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_10, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 11", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_11, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 12", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_12, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 13", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_13, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 14", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_14, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Custom Setting 15", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_15, + ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_ENUM_EXT("Ultrasound Tx Port", + elliptic_enum[0], + elliptic_ultrasound_tx_port_get, + elliptic_ultrasound_tx_port_set), + SOC_ENUM_EXT("Ultrasound Rx Port", + elliptic_enum[0], + elliptic_ultrasound_rx_port_get, + elliptic_ultrasound_rx_port_set), + SOC_SINGLE_EXT("Ultrasound Suspend", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_SUSPEND, + 1, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Input", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_ENABLED, + 1, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Output", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_OUTPUT_ENABLED, + 1, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Event", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_EXTERNAL_EVENT, + 256, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Calibration Method", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CALIBRATION_METHOD, + 256, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + + SND_SOC_BYTES_EXT("Ultrasound ML", + ELLIPTIC_ML_DATA_SIZE, + elliptic_ml_data_get, + elliptic_ml_data_put), + + SOC_SINGLE_EXT("Ultrasound Debug Mode", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_DEBUG_MODE, + 256, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SOC_SINGLE_EXT("Ultrasound Context", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CONTEXT, + ELLIPTIC_SYSTEM_CONFIGURATION_MAX_CONTEXT_VALUE, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + SND_SOC_BYTES_EXT("Ultrasound Sensor Data", + ELLIPTIC_SENSOR_DATA_SIZE, + elliptic_sensor_data_get, + elliptic_sensor_data_put), + + SOC_SINGLE_EXT("Ultrasound Capture", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_CAPTURE, + 256, + -1, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + + SOC_SINGLE_EXT("Ultrasound Tx Channels", + ELLIPTIC_SYSTEM_CONFIGURATION, + ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_CHANNELS, + 16, + 0, + elliptic_system_configuration_param_get, + elliptic_system_configuration_param_put), + +}; + + + +unsigned int elliptic_add_platform_controls(void *platform) +{ + const unsigned int num_controls = + ARRAY_SIZE(ultrasound_filter_mixer_controls); + + if (platform != NULL) { + snd_soc_add_platform_controls( + (struct snd_soc_platform *)platform, + ultrasound_filter_mixer_controls, + num_controls); + } else { + EL_PRINT_E("pointer is NULL"); + } + + return num_controls; +} +EXPORT_SYMBOL(elliptic_add_platform_controls); + +int elliptic_trigger_version_msg(void) +{ + int32_t msg[3] = {ESCPT_ENGINE_VERSION, 0, 0}; + + return elliptic_data_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} + +int elliptic_trigger_branch_msg(void) +{ + int32_t msg[3] = {ESCPT_BUILD_BRANCH, 0, 0}; + + return elliptic_data_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} + +int elliptic_trigger_tag_msg(void) +{ + int32_t msg[3] = {ESCPT_ENGINE_TAG, 0, 0}; + + return elliptic_data_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} + +int elliptic_trigger_diagnostics_msg(void) +{ + int32_t msg[3] = {ESCPT_ENGINE_DIAGNOSTICS, 0, 0}; + + return elliptic_data_write( + ELLIPTIC_ULTRASOUND_SET_PARAMS, + (const char *)msg, sizeof(msg)); +} diff --git a/techpack/audio/dsp/elliptic/elliptic_sysfs.c b/techpack/audio/dsp/elliptic/elliptic_sysfs.c new file mode 100755 index 000000000000..882bda0c4b85 --- /dev/null +++ b/techpack/audio/dsp/elliptic/elliptic_sysfs.c @@ -0,0 +1,635 @@ +#include +#include +#include +#include +#include +#include +#include +#include "elliptic_version.h" +#include + + +#define ELLIPTIC_DIAGNOSTICS_DATA_SECTION_COUNT 16 +#define ELLIPTIC_CALIBRATION_MAX_DISPLAY_COUNT 96 +#define ELLIPTIC_ML_DISPLAY_COUNT 16 + +static int kobject_create_and_add_failed; +static int sysfs_create_group_failed; + +extern struct elliptic_system_configuration_parameters_cache + elliptic_system_configuration_cache; + +static ssize_t calibration_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + + ssize_t result; + + struct elliptic_shared_data_block *calibration_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_CALIBRATION_DATA); + + if (calibration_obj == NULL) { + EL_PRINT_E("calibration_obj is NULL"); + return -EINVAL; + } + + if (count > calibration_obj->size) { + EL_PRINT_E("write length %zu larger than buffer", count); + return 0; + } + + memcpy(calibration_obj->buffer, buf, count); + result = (ssize_t)count; + return result; +} + +static ssize_t calibration_v2_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + + ssize_t result; + + struct elliptic_shared_data_block *calibration_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_CALIBRATION_V2_DATA); + + if (calibration_obj == NULL) { + EL_PRINT_E("calibration_obj is NULL"); + return -EINVAL; + } + + if (count > calibration_obj->size) { + EL_PRINT_E("write length %zu larger than buffer", count); + return 0; + } + + memcpy(calibration_obj->buffer, buf, count); + result = (ssize_t)count; + return result; +} + +static ssize_t diagnostics_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + + ssize_t result; + + struct elliptic_shared_data_block *diagnostics_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_DIAGNOSTICS_DATA); + + if (diagnostics_obj == NULL) { + EL_PRINT_E("diagnostics_obj is NULL"); + return -EINVAL; + } + + if (count > diagnostics_obj->size) { + EL_PRINT_E("write length %zu larger than buffer", count); + return 0; + } + + memcpy(diagnostics_obj->buffer, buf, count); + result = (ssize_t)count; + return result; +} + +static ssize_t ml_store(struct device *dev, + struct device_attribute *attr, const char *buf, size_t count) { + + ssize_t result; + + struct elliptic_shared_data_block *ml_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_ML_DATA); + + if (ml_obj == NULL) { + EL_PRINT_E("ml_obj is NULL"); + return -EINVAL; + } + + if (count > ml_obj->size) { + EL_PRINT_E("write length %zu larger than buffer", count); + return 0; + } + + memcpy(ml_obj->buffer, buf, count); + result = (ssize_t)count; + return result; +} + +static ssize_t calibration_show_core(struct device *dev, + struct device_attribute *attr, char *buf, int pretty) +{ + ssize_t result; + int length; + int i; + uint8_t *caldata; + + struct elliptic_shared_data_block *calibration_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_CALIBRATION_DATA); + + if (kobject_create_and_add_failed) + EL_PRINT_E("kobject_create_and_add_failed"); + + if (sysfs_create_group_failed) + EL_PRINT_E("sysfs_create_group_failed"); + + if (calibration_obj == NULL) { + EL_PRINT_E("calibration_obj is NULL"); + return -EINVAL; + } + + if (calibration_obj->size > PAGE_SIZE) { + EL_PRINT_E("calibration_obj->size > PAGE_SIZE"); + return -EINVAL; + } + + caldata = (uint8_t *)calibration_obj->buffer; + length = 0; + if (pretty) { + if (caldata[0] == 0xDE && + caldata[1] == 0xAD) { + length += snprintf(buf + length, PAGE_SIZE - length, + "Calibration Data: not loaded"); + } else { + length += snprintf(buf + length, PAGE_SIZE - length, + "Calibration Data: "); + for (i = 0; i < calibration_obj->size; ++i) + length += snprintf(buf + length, PAGE_SIZE - length, + "0x%02x ", caldata[i]); + } + } else { + for (i = 0; i < calibration_obj->size; ++i) + length += snprintf(buf + length, PAGE_SIZE - length, + "0x%02x ", caldata[i]); + } + length += snprintf(buf + length, PAGE_SIZE - length, "\n\n"); + result = (ssize_t)length; + return result; +} + +static ssize_t calibration_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return calibration_show_core(dev, attr, buf, 0); +} + +static ssize_t calibration_v2_show_core(struct device *dev, + struct device_attribute *attr, char *buf, int pretty) +{ + ssize_t result; + int length; + int i; + uint8_t *caldata; + + struct elliptic_shared_data_block *calibration_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_CALIBRATION_V2_DATA); + + if (kobject_create_and_add_failed) + EL_PRINT_E("kobject_create_and_add_failed"); + + if (sysfs_create_group_failed) + EL_PRINT_E("sysfs_create_group_failed"); + + if (calibration_obj == NULL) { + EL_PRINT_E("calibration_obj is NULL"); + return -EINVAL; + } + + if (calibration_obj->size > PAGE_SIZE) { + EL_PRINT_E("calibration_obj->size > PAGE_SIZE"); + return -EINVAL; + } + + caldata = (uint8_t *)calibration_obj->buffer; + length = 0; + if (pretty) { + if (caldata[0] == 0xDE && + caldata[1] == 0xAD) { + length += snprintf(buf + length, PAGE_SIZE - length, + "Calibration Ext Data: not loaded"); + } else { + int j = (ELLIPTIC_CALIBRATION_V2_DATA_SIZE>>2) - 1; + + length += snprintf(buf + length, PAGE_SIZE - length, + "Calibration Ext Data: "); + for (i = 0; i < ELLIPTIC_CALIBRATION_MAX_DISPLAY_COUNT; ++i) + length += snprintf(buf + length, PAGE_SIZE - length, + "0x%02x ", caldata[i]); + length += snprintf(buf + length, PAGE_SIZE - length, + "\nTruncated at %d", + ELLIPTIC_CALIBRATION_MAX_DISPLAY_COUNT); + length += snprintf(buf + length, PAGE_SIZE - length, + "\nmisc: %u %u %u %u %u %u %u %u\n", + caldata[j-7], caldata[j-6], caldata[j-5], + caldata[j-4], caldata[j-3], caldata[j-2], + caldata[j-1], caldata[j]); + } + } else { + for (i = 0; i < calibration_obj->size; ++i) + length += snprintf(buf + length, PAGE_SIZE - length, + "0x%02x ", caldata[i]); + } + length += snprintf(buf + length, PAGE_SIZE - length, "\n\n"); + result = (ssize_t)length; + return result; +} + +static ssize_t calibration_v2_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return calibration_v2_show_core(dev, attr, buf, 0); +} + +static ssize_t diagnostics_show_core(struct device *dev, + struct device_attribute *attr, char *buf, int pretty) +{ + ssize_t result; + int length; + uint32_t *data32; + int i; + + struct elliptic_shared_data_block *diagnostics_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_DIAGNOSTICS_DATA); + + if (kobject_create_and_add_failed) + EL_PRINT_E("kobject_create_and_add_failed"); + + if (sysfs_create_group_failed) + EL_PRINT_E("sysfs_create_group_failed"); + + if (diagnostics_obj == NULL) { + EL_PRINT_E("diagnostics_obj is NULL"); + return -EINVAL; + } + + if (diagnostics_obj->size > PAGE_SIZE) { + EL_PRINT_E("diagnostics_obj->size > PAGE_SIZE"); + return -EINVAL; + } + + length = 0; + data32 = (uint32_t *)diagnostics_obj->buffer; + + if (pretty) { + length += snprintf(buf + length, PAGE_SIZE - length, + "Diagnostics:\n counters:\n"); + for (i = 0; i < ELLIPTIC_DIAGNOSTICS_DATA_SECTION_COUNT; i++) + length += snprintf(buf + length, PAGE_SIZE - length, " %u %u %u %u\n", + data32[4*i], data32[4*i+1], data32[4*i+2], data32[4*i+3]); + } else { + for (i = 0; i < (diagnostics_obj->size >> 4); ++i) + length += snprintf(buf + length, PAGE_SIZE - length, " %u %u %u %u\n", + data32[4*i], data32[4*i+1], data32[4*i+2], data32[4*i+3]); + } + length += snprintf(buf + length, PAGE_SIZE - length, "\n\n"); + result = (ssize_t)length; + return result; +} + +static ssize_t diagnostics_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return diagnostics_show_core(dev, attr, buf, 0); +} + +static ssize_t ml_show_core(struct device *dev, + struct device_attribute *attr, char *buf, int pretty) +{ + ssize_t result; + int length; + int i; + uint32_t *mldata; + + struct elliptic_shared_data_block *ml_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_ML_DATA); + + if (kobject_create_and_add_failed) + EL_PRINT_E("kobject_create_and_add_failed"); + + if (sysfs_create_group_failed) + EL_PRINT_E("sysfs_create_group_failed"); + + if (ml_obj == NULL) { + EL_PRINT_E("ml_obj is NULL"); + return -EINVAL; + } + + if (ml_obj->size > PAGE_SIZE) { + EL_PRINT_E("ml_obj->size > PAGE_SIZE"); + return -EINVAL; + } + + mldata = (uint32_t *)ml_obj->buffer; + length = 0; + if (pretty) { + if (mldata[0] == 0x0 && + mldata[1] == 0x0) { + length += snprintf(buf + length, PAGE_SIZE - length, + "ML Data: not loaded"); + } else { + length += snprintf(buf + length, PAGE_SIZE - length, + "ML Data: "); + for (i = 0; i < ELLIPTIC_ML_DISPLAY_COUNT; ++i) + length += snprintf(buf + length, PAGE_SIZE - length, + "0x%08x ", mldata[i]); + length += snprintf(buf + length, PAGE_SIZE - length, + "\nTruncated at %d", + ELLIPTIC_ML_DISPLAY_COUNT); + } + } else { + int values = ml_obj->size >> 2; + + for (i = 0; i < values; ++i) + length += snprintf(buf + length, PAGE_SIZE - length, + "0x%08x ", mldata[i]); + } + length += snprintf(buf + length, PAGE_SIZE - length, "\n\n"); + result = (ssize_t)length; + return result; +} + +static ssize_t ml_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return ml_show_core(dev, attr, buf, 0); +} + + +static ssize_t version_show_core(struct device *dev, + struct device_attribute *attr, char *buf, int pretty) +{ + ssize_t result; + struct elliptic_engine_version_info *version_info; + int length; + + struct elliptic_shared_data_block *version_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_VERSION_INFO); + + if (kobject_create_and_add_failed) + EL_PRINT_E("kobject_create_and_add_failed"); + + if (sysfs_create_group_failed) + EL_PRINT_E("sysfs_create_group_failed"); + + if (version_obj == NULL) { + EL_PRINT_E("version_obj is NULL"); + return -EINVAL; + } + + if (version_obj->size > PAGE_SIZE) { + EL_PRINT_E("version_obj->size > PAGE_SIZE"); + return -EINVAL; + } + + version_info = (struct elliptic_engine_version_info *) + version_obj->buffer; + + if (pretty) { + if (version_info->major == 0xDE && + version_info->minor == 0xAD) { + length = snprintf(buf, PAGE_SIZE, "Version: unknown\n"); + } else { + length = snprintf(buf, PAGE_SIZE, "Version: %d.%d.%d.%d\n", + version_info->major, version_info->minor, + version_info->build, version_info->revision); + } + } else { + length = snprintf(buf, PAGE_SIZE, "%d.%d.%d.%d\n", + version_info->major, version_info->minor, + version_info->build, version_info->revision); + } + result = (ssize_t)length; + return result; +} + +static ssize_t version_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return version_show_core(dev, attr, buf, 0); +} + + +static ssize_t branch_show_core(struct device *dev, + struct device_attribute *attr, char *buf, int pretty) +{ + int length; + + struct elliptic_shared_data_block *branch_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_BRANCH_INFO); + + if (branch_obj == NULL) { + EL_PRINT_E("branch_obj not found"); + return 0; + } + + if (branch_obj->size > PAGE_SIZE) { + EL_PRINT_E("branch_obj->size > PAGE_SIZE"); + return -EINVAL; + } + if (pretty) { + length = snprintf(buf, PAGE_SIZE - 1, "Branch: %s\n", + (const char *)(branch_obj->buffer)); + } else { + length = snprintf(buf, PAGE_SIZE - 1, "%s\n", + (const char *)(branch_obj->buffer)); + } + + return (ssize_t)length; +} + +static ssize_t branch_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return branch_show_core(dev, attr, buf, 0); +} + +static ssize_t tag_show_core(struct device *dev, + struct device_attribute *attr, char *buf, int pretty) +{ + int length; + + struct elliptic_shared_data_block *tag_obj = + elliptic_get_shared_obj(ELLIPTIC_OBJ_ID_TAG_INFO); + + if (tag_obj == NULL) { + EL_PRINT_E("tag_obj not found"); + return 0; + } + + if (tag_obj->size > PAGE_SIZE) { + EL_PRINT_E("tag_obj->size > PAGE_SIZE"); + return -EINVAL; + } + if (pretty) { + length = snprintf(buf, PAGE_SIZE - 1, "Tag: %s\n", + (const char *)(tag_obj->buffer)); + } else { + length = snprintf(buf, PAGE_SIZE - 1, "%s\n", + (const char *)(tag_obj->buffer)); + } + + return (ssize_t)length; +} + +static ssize_t tag_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return tag_show_core(dev, attr, buf, 0); +} + +static ssize_t cache_show(char *buf, int pretty) +{ + struct elliptic_system_configuration_parameters_cache *cache = + &elliptic_system_configuration_cache; + + int length; + + length = snprintf(buf, PAGE_SIZE - 1, "Cache:\n"); + length += snprintf(buf + length, PAGE_SIZE - 1, " mi:%d\n", + cache->microphone_index); + length += snprintf(buf + length, PAGE_SIZE - 1, " om:%d\n", + cache->operation_mode); + length += snprintf(buf + length, PAGE_SIZE - 1, " omf:%d\n", + cache->operation_mode_flags); + length += snprintf(buf + length, PAGE_SIZE - 1, " cs:%d\n", + cache->calibration_state); + length += snprintf(buf + length, PAGE_SIZE - 1, " cp:%d\n", + cache->calibration_profile); + length += snprintf(buf + length, PAGE_SIZE - 1, " ug:%d\n", + cache->ultrasound_gain); + length += snprintf(buf + length, PAGE_SIZE - 1, " ll:%d\n", + cache->log_level); + length += snprintf(buf + length, PAGE_SIZE - 1, " es:%d\n", + cache->engine_suspend); + + return (ssize_t)length; +} + +static ssize_t opmode_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int length; + ssize_t result; + + struct elliptic_system_configuration_parameters_cache *cache = + &elliptic_system_configuration_cache; + + length += snprintf(buf + length, PAGE_SIZE - 1, "%d\n", + cache->operation_mode); + result = (ssize_t)length; + return result; +} + +static ssize_t opmode_flags_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int length; + ssize_t result; + struct elliptic_system_configuration_parameters_cache *cache = + &elliptic_system_configuration_cache; + + length += snprintf(buf + length, PAGE_SIZE - 1, "%d\n", + cache->operation_mode_flags); + result = (ssize_t)length; + return result; +} + +static ssize_t driver_version_show(char *buf) +{ + int length; + + length = snprintf(buf, PAGE_SIZE, "Driver version: %s-%s (%s)\n", + build_name, build_number, build_source_version); + + return (ssize_t)length; +} + +static ssize_t state_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + int length = 0; + + length += driver_version_show(buf + length); + length += version_show_core(dev, attr, buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + length += branch_show_core(dev, attr, buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + length += tag_show_core(dev, attr, buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + length += calibration_show_core(dev, attr, buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + length += calibration_v2_show_core(dev, attr, buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + length += diagnostics_show_core(dev, attr, buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + length += ml_show_core(dev, attr, buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + length += cache_show(buf + length, 1); + if (length > PAGE_SIZE) + return (ssize_t)0; + return (ssize_t)length; +} + +static struct device_attribute calibration_attr = __ATTR_RW(calibration); +static struct device_attribute version_attr = __ATTR_RO(version); +static struct device_attribute branch_attr = __ATTR_RO(branch); +static struct device_attribute calibration_v2_attr = __ATTR_RW(calibration_v2); +static struct device_attribute diagnostics_attr = __ATTR_RW(diagnostics); +static struct device_attribute state_attr = __ATTR_RO(state); +static struct device_attribute tag_attr = __ATTR_RO(tag); +static struct device_attribute ml_attr = __ATTR_RW(ml); +static struct device_attribute opmode_attr = __ATTR_RO(opmode); +static struct device_attribute opmode_flags_attr = __ATTR_RO(opmode_flags); + +static struct attribute *elliptic_attrs[] = { + &calibration_attr.attr, + &version_attr.attr, + &branch_attr.attr, + &calibration_v2_attr.attr, + &diagnostics_attr.attr, + &state_attr.attr, + &tag_attr.attr, + &ml_attr.attr, + &opmode_attr.attr, + &opmode_flags_attr.attr, + NULL, +}; + +static struct attribute_group elliptic_attr_group = { + .name = ELLIPTIC_SYSFS_ENGINE_FOLDER, + .attrs = elliptic_attrs, +}; + +static struct kobject *elliptic_sysfs_kobj; + +int elliptic_initialize_sysfs(void) +{ + int err; + + elliptic_sysfs_kobj = kobject_create_and_add(ELLIPTIC_SYSFS_ROOT_FOLDER, + kernel_kobj->parent); + + if (!elliptic_sysfs_kobj) { + kobject_create_and_add_failed = 1; + EL_PRINT_E("failed to create kobj"); + return -ENOMEM; + } + + err = sysfs_create_group(elliptic_sysfs_kobj, &elliptic_attr_group); + + if (err) { + sysfs_create_group_failed = 1; + EL_PRINT_E("failed to create sysfs group"); + kobject_put(elliptic_sysfs_kobj); + return -ENOMEM; + } + + return 0; +} + +void elliptic_cleanup_sysfs(void) +{ + kobject_put(elliptic_sysfs_kobj); +} diff --git a/techpack/audio/dsp/elliptic/elliptic_version.h b/techpack/audio/dsp/elliptic/elliptic_version.h new file mode 100755 index 000000000000..1c8eb9af005d --- /dev/null +++ b/techpack/audio/dsp/elliptic/elliptic_version.h @@ -0,0 +1,8 @@ +#ifndef ELLIPTIC_VERSION_H +#define ELLIPTIC_VERSION_H + +#define build_name "Elliptic.LinuxKernelDriver.VendorDLKM.master" +#define build_number "20181016.1" +#define build_source_version "e5e26691554bba9b1438ec3d7e0cc55dfb296bb8" + +#endif //ELLIPTIC_VERSION_H diff --git a/techpack/audio/dsp/elliptic/io_modules/msm/elliptic_data_msm_io.c b/techpack/audio/dsp/elliptic/io_modules/msm/elliptic_data_msm_io.c new file mode 100755 index 000000000000..f5443903e88e --- /dev/null +++ b/techpack/audio/dsp/elliptic/io_modules/msm/elliptic_data_msm_io.c @@ -0,0 +1,108 @@ +/** + * Copyright Elliptic Labs + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +/* includes the file structure, that is, file open read close */ +#include + +/* include the character device, makes cdev avilable */ +#include +#include + +/* includes copy_user vice versa */ +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#define IO_PING_PONG_BUFFER_SIZE 512 +#define AFE_MSM_RX_PSEUDOPORT_ID 0x8001 +#define AFE_MSM_TX_PSEUDOPORT_ID 0x8002 + +struct elliptic_msm_io_device { +}; + +/* static struct elliptic_msm_io_device io_device;*/ + + +int elliptic_data_io_initialize(void) +{ + return 0; +} + +int elliptic_data_io_cleanup(void) +{ + return 0; +} +int elliptic_io_open_port(int portid) +{ + if (portid == ULTRASOUND_RX_PORT_ID) + return afe_start_pseudo_port(AFE_MSM_RX_PSEUDOPORT_ID); + else + return afe_start_pseudo_port(AFE_MSM_TX_PSEUDOPORT_ID); +} + +int elliptic_io_close_port(int portid) +{ + if (portid == ULTRASOUND_RX_PORT_ID) + return afe_stop_pseudo_port(AFE_MSM_RX_PSEUDOPORT_ID); + else + return afe_stop_pseudo_port(AFE_MSM_TX_PSEUDOPORT_ID); +} + +int32_t elliptic_data_io_write(uint32_t message_id, const char *data, + size_t data_size) +{ + int32_t result = 0; + + /* msm_pcm_routing_acquire_lock(); */ + + result = ultrasound_apr_set_parameter(ELLIPTIC_PORT_ID, + message_id, (u8 *)data, + (int32_t)data_size); + + /* msm_pcm_routing_release_lock();*/ + return result; +} + +int32_t elliptic_data_io_transact(uint32_t message_id, const char *data, + size_t data_size, char *output_data, size_t output_data_size) +{ + pr_err("%s : unimplemented\n", __func__); + return -EINVAL; +} diff --git a/techpack/audio/dsp/elliptic/io_modules/userspace/Makefile b/techpack/audio/dsp/elliptic/io_modules/userspace/Makefile new file mode 100755 index 000000000000..907ddc20a1d9 --- /dev/null +++ b/techpack/audio/dsp/elliptic/io_modules/userspace/Makefile @@ -0,0 +1,2 @@ +# TODO: add config parameter for which io module to build +#obj-y += elliptic_data_io.o diff --git a/techpack/audio/dsp/elliptic/io_modules/userspace/elliptic_data_userspace_ctrl.c b/techpack/audio/dsp/elliptic/io_modules/userspace/elliptic_data_userspace_ctrl.c new file mode 100755 index 000000000000..93abf6e4c304 --- /dev/null +++ b/techpack/audio/dsp/elliptic/io_modules/userspace/elliptic_data_userspace_ctrl.c @@ -0,0 +1,271 @@ +/** + * Copyright Elliptic Labs + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +/* includes the file structure, that is, file open read close */ +#include + +/* include the character device, makes cdev avilable */ +#include +#include + +/* includes copy_user vice versa */ +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static dev_t elliptic_userspace_ctrl_major; +#define USERSPACE_CTRL_IO_DEVICE_NAME "elliptic_us_ctrl_io" +struct elliptic_userspace_ctrl_device { + struct cdev cdev; + struct semaphore sem; + int ping_pong_idx; + size_t ping_pong_buffer_size[2]; + uint8_t ping_pong_buffer[2][ELLIPTIC_MSG_BUF_SIZE]; + wait_queue_head_t data_available; + struct mutex data_lock; + atomic_t data_state; +}; + + + +static struct elliptic_userspace_ctrl_device ctrl_device; + +static uint8_t *get_ping_buffer(struct elliptic_userspace_ctrl_device *dev, + /*out parameter*/ size_t *data_size) +{ + if (data_size != NULL) + *data_size = dev->ping_pong_buffer_size[dev->ping_pong_idx]; + + return dev->ping_pong_buffer[dev->ping_pong_idx]; +} + +static uint8_t *get_pong_buffer(struct elliptic_userspace_ctrl_device *dev, +/*out parameter*/ size_t *data_size) +{ + if (data_size != NULL) + *data_size = dev->ping_pong_buffer_size[1 - dev->ping_pong_idx]; + + return dev->ping_pong_buffer[1 - dev->ping_pong_idx]; +} + + +static void set_pong_buffer_size(struct elliptic_userspace_ctrl_device *dev, + size_t data_size) +{ + dev->ping_pong_buffer_size[1 - dev->ping_pong_idx] = data_size; +} + +static void swap_ping_pong(struct elliptic_userspace_ctrl_device *dev) +{ + dev->ping_pong_idx = 1 - dev->ping_pong_idx; +} + +static int device_open(struct inode *inode, struct file *filp) +{ + if (inode->i_cdev != &ctrl_device.cdev) { + pr_warn("elliptic : dev pointer mismatch\n"); + return -ENODEV; /* No such device */ + } + + if (down_interruptible(&ctrl_device.sem) != 0) + return -EEXIST; + EL_PRINT_I("Opened device %s", USERSPACE_CTRL_IO_DEVICE_NAME); + return 0; +} + +static ssize_t device_read(struct file *fp, char __user *buff, + size_t user_buf_length, loff_t *ppos) +{ + size_t bytes_read; + unsigned long copy_result; + uint8_t *ping_buffer; + int result; + + if (user_buf_length < ELLIPTIC_MSG_BUF_SIZE) + EL_PRINT_E("user space buffer user_buf_length too small : %zu", + user_buf_length); + + bytes_read = 0; + copy_result = 0; + ping_buffer = NULL; + + result = wait_event_interruptible(ctrl_device.data_available, + atomic_read(&ctrl_device.data_state) != 0); + if (result == 0) { + const int state = atomic_read(&ctrl_device.data_state); + + if (state > 0) { + result = mutex_lock_interruptible( + &ctrl_device.data_lock); + if (result == 0) { + swap_ping_pong(&ctrl_device); + + ping_buffer = get_ping_buffer( + &ctrl_device, &bytes_read); + + if (bytes_read > user_buf_length) { + EL_PRINT_E( + "ping buffer size %zu larger than user buffer", + bytes_read); + goto fail; + } + + copy_result = copy_to_user(buff, ping_buffer, + bytes_read); + if (copy_result > 0) { + EL_PRINT_E("Failed copy to user"); + goto fail; + } + + atomic_set(&ctrl_device.data_state, 0); + + mutex_unlock(&ctrl_device.data_lock); + } else if (result == -EINTR) { + EL_PRINT_E("lock interrupted"); + } else { + EL_PRINT_E("lock error = %d", result); + } + } else { + EL_PRINT_W("state = %d", state); + atomic_set(&ctrl_device.data_state, 0); + } + } else if (result == -ERESTARTSYS) { + EL_PRINT_E("interrupted"); + } else { + EL_PRINT_E("wait_event error = %d", result); + } + return bytes_read; +fail: + atomic_set(&ctrl_device.data_state, 0); + mutex_unlock(&ctrl_device.data_lock); + return 0; +} + +static int device_close(struct inode *inode, struct file *filp) +{ + up(&ctrl_device.sem); + EL_PRINT_I("Closed device %s", USERSPACE_CTRL_IO_DEVICE_NAME); + return 0; +} + +static const struct file_operations +elliptic_userspace_ctrl_fops = { + .owner = THIS_MODULE, + .open = device_open, + .read = device_read, + .release = device_close, +}; + +int elliptic_userspace_ctrl_driver_init(void) +{ + struct device *device; + dev_t device_number; + int err; + + err = alloc_chrdev_region( + &device_number, 0, 1, USERSPACE_CTRL_IO_DEVICE_NAME); + + if (err < 0) { + pr_err("failed to allocate chrdev region\n"); + return err; + } + + elliptic_userspace_ctrl_major = MAJOR(device_number); + + device_number = MKDEV(elliptic_userspace_ctrl_major, 0); + device = device_create( + elliptic_class, NULL, device_number, + NULL, USERSPACE_CTRL_IO_DEVICE_NAME); + + if (IS_ERR(device)) { + unregister_chrdev( + elliptic_userspace_ctrl_major, + USERSPACE_CTRL_IO_DEVICE_NAME); + EL_PRINT_E("Failed to create the device\n"); + return PTR_ERR(device); + } + + cdev_init(&ctrl_device.cdev, &elliptic_userspace_ctrl_fops); + ctrl_device.cdev.owner = THIS_MODULE; + err = cdev_add(&ctrl_device.cdev, device_number, 1); + if (err) { + EL_PRINT_W("error %d while trying to add %s%d", + err, ELLIPTIC_DEVICENAME, 0); + return err; + } + + sema_init(&ctrl_device.sem, 1); + mutex_init(&ctrl_device.data_lock); + init_waitqueue_head(&ctrl_device.data_available); + return 0; +} + +void elliptic_userspace_ctrl_driver_exit(void) +{ + BUG_ON(elliptic_class == NULL); + device_destroy(elliptic_class, MKDEV(elliptic_userspace_ctrl_major, 0)); + cdev_del(&ctrl_device.cdev); + unregister_chrdev(elliptic_userspace_ctrl_major, + USERSPACE_CTRL_IO_DEVICE_NAME); + up(&ctrl_device.sem); +} + +int32_t elliptic_userspace_ctrl_write(uint32_t message_id, + const char *data, size_t data_size){ + uint8_t *pong_buffer; + + if (data_size > ELLIPTIC_MSG_BUF_SIZE) { + EL_PRINT_E("data size : %zu larger than buf size : %zu", + data_size, (size_t)ELLIPTIC_MSG_BUF_SIZE); + + return -EINVAL; + } + mutex_lock(&ctrl_device.data_lock); + + pong_buffer = get_pong_buffer(&ctrl_device, NULL); + set_pong_buffer_size(&ctrl_device, data_size); + + memcpy(pong_buffer, data, data_size); + wake_up_interruptible(&ctrl_device.data_available); + atomic_set(&ctrl_device.data_state, 1); + mutex_unlock(&ctrl_device.data_lock); + + return 0; +} + + diff --git a/techpack/audio/dsp/elliptic/io_modules/userspace/elliptic_data_userspace_io.c b/techpack/audio/dsp/elliptic/io_modules/userspace/elliptic_data_userspace_io.c new file mode 100755 index 000000000000..7f207d98a644 --- /dev/null +++ b/techpack/audio/dsp/elliptic/io_modules/userspace/elliptic_data_userspace_io.c @@ -0,0 +1,149 @@ +/** + * Copyright Elliptic Labs + * + */ + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +/* includes the file structure, that is, file open read close */ +#include + +/* include the character device, makes cdev avilable */ +#include +#include + +/* includes copy_user vice versa */ +#include + +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +static dev_t elliptic_userspace_major; +#define USERSPACE_IO_DEVICE_NAME "elliptic_us_io" +struct elliptic_userspace_device { + struct cdev cdev; + struct semaphore sem; +}; + +static struct elliptic_userspace_device io_device; + +static int device_open(struct inode *inode, struct file *filp) +{ + if (inode->i_cdev != &io_device.cdev) { + pr_warn("elliptic : dev pointer mismatch\n"); + return -ENODEV; /* No such device */ + } + + if (down_interruptible(&io_device.sem) != 0) + return -EEXIST; + EL_PRINT_I("Opened device %s", USERSPACE_IO_DEVICE_NAME); + return 0; +} + +static ssize_t device_write(struct file *fp, const char __user *buff, + size_t length, loff_t *ppos) +{ + int push_result; + + push_result = elliptic_data_push( + ELLIPTIC_ALL_DEVICES, buff, length, ELLIPTIC_DATA_PUSH_FROM_USERSPACE); + + return push_result == 0 ? (ssize_t)length : (ssize_t)(-1); +} + +static int device_close(struct inode *inode, struct file *filp) +{ + up(&io_device.sem); + EL_PRINT_I("Closed device %s", USERSPACE_IO_DEVICE_NAME); + return 0; +} + +static const struct file_operations +elliptic_userspace_fops = { + .owner = THIS_MODULE, + .open = device_open, + .write = device_write, + .release = device_close, +}; + +int elliptic_userspace_io_driver_init(void) +{ + struct device *device; + dev_t device_number; + int err; + + err = alloc_chrdev_region( + &device_number, 0, 1, USERSPACE_IO_DEVICE_NAME); + + if (err < 0) { + pr_err("failed to allocate chrdev region\n"); + return err; + } + + elliptic_userspace_major = MAJOR(device_number); + + device_number = MKDEV(elliptic_userspace_major, 0); + device = device_create( + elliptic_class, NULL, device_number, + NULL, USERSPACE_IO_DEVICE_NAME); + + if (IS_ERR(device)) { + unregister_chrdev( + elliptic_userspace_major, USERSPACE_IO_DEVICE_NAME); + pr_err("Failed to create the device\n"); + return PTR_ERR(device); + } + + cdev_init(&io_device.cdev, &elliptic_userspace_fops); + io_device.cdev.owner = THIS_MODULE; + err = cdev_add(&io_device.cdev, device_number, 1); + if (err) { + EL_PRINT_W("error %d while trying to add %s%d", + err, ELLIPTIC_DEVICENAME, 0); + return err; + } + + sema_init(&io_device.sem, 1); + return 0; +} + +void elliptic_userspace_io_driver_exit(void) +{ + BUG_ON(elliptic_class == NULL); + device_destroy(elliptic_class, MKDEV(elliptic_userspace_major, 0)); + cdev_del(&io_device.cdev); + unregister_chrdev(elliptic_userspace_major, USERSPACE_IO_DEVICE_NAME); + up(&io_device.sem); +} + + diff --git a/techpack/audio/dsp/msm-cirrus-playback.c b/techpack/audio/dsp/msm-cirrus-playback.c new file mode 100644 index 000000000000..251bce5d9d51 --- /dev/null +++ b/techpack/audio/dsp/msm-cirrus-playback.c @@ -0,0 +1,1539 @@ +/* Copyright (c) 2015, The Linux Foundation. All rights reserved. +* This program is free software; you can redistribute it and/or modify +* it under the terms of the GNU General Public License version 2 and +* only 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. +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + + +#include +#include +#include +/* includes the file structure, that is, file open read close */ +#include + +/* include the character device, makes cdev avilable */ +#include +#include + +/* includes copy_user vice versa */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "../asoc/msm-pcm-routing-v2.h" +#include +#include +#include +#include +#include + +#undef CONFIG_OF + +#undef pr_info +#undef pr_err +#undef pr_debug +#define pr_debug(fmt, args...) printk(KERN_INFO "[CSPL] " pr_fmt(fmt), ##args) +#define pr_info(fmt, args...) printk(KERN_INFO "[CSPL] " pr_fmt(fmt), ##args) +#define pr_err(fmt, args...) printk(KERN_ERR "[CSPL] " pr_fmt(fmt), ##args) + +#define CRUS_TX_CONFIG "crus_sp_tx%d.bin" +#define CRUS_RX_CONFIG "crus_sp_rx%d.bin" + +#define CIRRUS_RX_GET_IODATA 0x00A1AF09 +#define CIRRUS_TX_GET_IODATA 0x00A1BF09 + +static struct crus_sp_ioctl_header crus_sp_hdr; + +static struct crus_control_t this_ctrl = { + .fb_port_index = 3, + .fb_port = AFE_PORT_ID_QUATERNARY_MI2S_TX, + .ff_port = AFE_PORT_ID_QUATERNARY_MI2S_RX, + .usecase_dt_count = MAX_TUNING_CONFIGS, + .ch_sw_duration = 30, + .ch_sw = 0, + .vol_atten = 0, + .prot_en = false, + .q6afe_rev = 3, // V3 as default +}; + + +static void *crus_gen_afe_get_header(int length, int port, int module, + int param) +{ + struct afe_custom_crus_get_config_v2_t *config = NULL; + int size = sizeof(struct afe_custom_crus_get_config_v2_t); + int index = afe_get_port_index(port); + uint16_t payload_size = sizeof(struct param_hdr_v2) + + length; + + /* Allocate memory for the message */ + config = kzalloc(size, GFP_KERNEL); + if (!config) + return NULL; + + /* Set header section */ + config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + config->hdr.pkt_size = size; + config->hdr.src_svc = APR_SVC_AFE; + config->hdr.src_domain = APR_DOMAIN_APPS; + config->hdr.src_port = 0; + config->hdr.dest_svc = APR_SVC_AFE; + config->hdr.dest_domain = APR_DOMAIN_ADSP; + config->hdr.dest_port = 0; + config->hdr.token = index; + config->hdr.opcode = AFE_PORT_CMD_GET_PARAM_V2; + + /* Set param section */ + config->param.port_id = (uint16_t) port; + + config->param.mem_hdr.data_payload_addr_lsw = 0; + config->param.mem_hdr.data_payload_addr_msw = 0; + config->param.mem_hdr.mem_map_handle = 0; + config->param.module_id = (uint32_t) module; + config->param.param_id = (uint32_t) param; + /* max data size of the param_ID/module_ID combination */ + config->param.payload_size = payload_size; + + /* Set data section */ + config->data.module_id = (uint32_t) module; + config->data.param_id = (uint32_t) param; + + /*remove for 855*/ + //config->data.reserved = 0; /* Must be set to 0 */ + /* actual size of the data for the module_ID/param_ID pair */ + config->data.param_size = length; + + return (void *)config; +} + + +static void *crus_gen_afe_set_header(int length, int port, int module, + int param) +{ + struct afe_custom_crus_set_config_v2_t *config = NULL; + int size = sizeof(struct afe_custom_crus_set_config_v2_t) + length; + int index = afe_get_port_index(port); + uint16_t payload_size = sizeof(struct param_hdr_v2) + + length; + + /* Allocate memory for the message */ + config = kzalloc(size, GFP_KERNEL); + if (!config) + return NULL; + + /* Set header section */ + config->hdr.hdr_field = APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, + APR_HDR_LEN(APR_HDR_SIZE), APR_PKT_VER); + config->hdr.pkt_size = size; + config->hdr.src_svc = APR_SVC_AFE; + config->hdr.src_domain = APR_DOMAIN_APPS; + config->hdr.src_port = 0; + config->hdr.dest_svc = APR_SVC_AFE; + config->hdr.dest_domain = APR_DOMAIN_ADSP; + config->hdr.dest_port = 0; + config->hdr.token = index; + config->hdr.opcode = AFE_PORT_CMD_SET_PARAM_V2; + + /* Set param section */ + config->param.port_id = (uint16_t) port; + config->param.mem_hdr.data_payload_addr_lsw = 0; + config->param.mem_hdr.data_payload_addr_msw = 0; + config->param.mem_hdr.mem_map_handle = 0; + /* max data size of the param_ID/module_ID combination */ + config->param.payload_size = payload_size; + + /* Set data section */ + config->data.module_id = (uint32_t) module; + config->data.param_id = (uint32_t) param; + + /*remove for 855*/ + //config->data.reserved = 0; /* Must be set to 0 */ + + /* actual size of the data for the module_ID/param_ID pair */ + config->data.param_size = length; + + return (void *)config; +} + +static int crus_afe_get_param(int port, int module, int param, int length, + void *data) +{ + struct afe_custom_crus_get_config_v2_t *config = NULL; + int index = afe_get_port_index(port); + int ret = 0, count = 0; + + pr_info("CRUS_SP: (get_param) module = 0x%08x, port = 0x%08x, param = 0x%08x\n", + module, port, param); + + config = (struct afe_custom_crus_get_config_v2_t *) + crus_gen_afe_get_header(length, port, module, param); + if (config == NULL) { + pr_err("CRUS_SP: Memory allocation failed\n"); + return -ENOMEM; + } + + mutex_lock(&this_ctrl.param_lock); + atomic_set(&this_ctrl.callback_wait, 0); + + this_ctrl.user_buffer = kzalloc(config->param.payload_size + 16, + GFP_KERNEL); + + ret = afe_apr_send_pkt_crus(config, index, 0); + if (ret) + pr_err("CRUS_SP: (get_param) failed with code %d\n", ret); + + /* Wait for afe callback to populate data */ + while (!atomic_read(&this_ctrl.callback_wait)) { + usleep_range(800, 1200); + if (count++ >= 1000) { + pr_err("CRUS_SP: AFE callback timeout\n"); + atomic_set(&this_ctrl.callback_wait, 1); + ret = -EINVAL; + goto exit; + } + } + + /* Copy from dynamic buffer to return buffer */ + memcpy((u8 *)data, &this_ctrl.user_buffer[4], length); + +exit: + kfree(this_ctrl.user_buffer); + mutex_unlock(&this_ctrl.param_lock); + kfree(config); + return ret; +} + + + +static int crus_afe_set_param(int port, int module, int param, int length, + void *data_ptr) +{ + struct afe_custom_crus_set_config_v2_t *config = NULL; + int index = afe_get_port_index(port); + int ret = 0; + + pr_info("CRUS_SP: (set_param) module = 0x%08x, port = 0x%08x, param = 0x%08x\n", + module, port, param); + + config = crus_gen_afe_set_header(length, port, module, param); + if (config == NULL) { + pr_err("CRUS_SP: Memory allocation failed\n"); + return -ENOMEM; + } + + memcpy((u8 *)config + sizeof(struct afe_custom_crus_set_config_v2_t), + (u8 *) data_ptr, length); + + ret = afe_apr_send_pkt_crus(config, index, 1); + if (ret) + pr_err("CRUS_SP: (set_param) failed with code %d\n", ret); + + kfree(config); + return ret; +} + + + +static int crus_afe_get_param_v3(int port, int module_id, + int param_id, uint32_t length, void *data) +{ + struct afe_port_cmd_get_param_v3 afe_get_param; + struct param_hdr_v3 param_hdr; + u16 port_id = 0; + int index = 0; + int ret = 0; + + pr_info("%s: port=0x%x, module=0x%x, param_id=0x%x, size=%d\n", + __func__, port, module_id, param_id, length); + + param_hdr.module_id = module_id; + param_hdr.instance_id = INSTANCE_ID_0; + param_hdr.param_id = param_id; + param_hdr.param_size = length; + + port_id = q6audio_get_port_id(port); + ret = q6audio_validate_port(port_id); + if (ret < 0) { + pr_err("%s: Not a valid port id = 0x%x ret %d\n", __func__, + port_id, ret); + return -EINVAL; + } + index = q6audio_get_port_index(port); + + //q6afe_get_params_v3 + memset(&afe_get_param, 0, sizeof(afe_get_param)); + afe_get_param.apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + afe_get_param.apr_hdr.pkt_size = sizeof(afe_get_param); + afe_get_param.apr_hdr.src_port = 0; + afe_get_param.apr_hdr.dest_port = 0; + afe_get_param.apr_hdr.token = index; + afe_get_param.apr_hdr.opcode = AFE_PORT_CMD_GET_PARAM_V3; + afe_get_param.port_id = port_id; + //if (mem_hdr != NULL) + // afe_get_param.mem_hdr = *mem_hdr; + /* Set param header in command, no payload in V3 */ + afe_get_param.param_hdr = param_hdr; + //q6afe_get_params_v3 end + + mutex_lock(&this_ctrl.param_lock); + atomic_set(&this_ctrl.callback_wait, 0); + this_ctrl.user_buffer = kzalloc(length + 64, + GFP_KERNEL); + atomic_set(cspl_afe.status, 0); + ret = apr_send_pkt(*cspl_afe.apr, (uint32_t *) &afe_get_param); + if (ret < 0) { + pr_err("%s: Setting param for port %d param[0x%x]failed\n", + __func__, port, param_id); + goto fail_cmd; + } + /* Wait for afe callback to populate data */ + while(!atomic_read(&this_ctrl.callback_wait)) + msleep(1); + +#if 0 + for (index = 0; index < length; index ++) + pr_info("[%d]=%d\n", index, this_ctrl.user_buffer[index]); + + pr_info("[5]=%s\n", &this_ctrl.user_buffer[5]); +#endif + /* copy from dynamic buffer to return buffer */ + memcpy((u8*)data, &this_ctrl.user_buffer[5], length); + pr_info("%s: Copied %d bytes data \n", __func__, length); + + ret = 0; +fail_cmd: + pr_info("%s: param_id %x status %d\n", __func__, param_id, ret); + mutex_unlock(&this_ctrl.param_lock); + kfree(this_ctrl.user_buffer); + return ret; +} + +static int crus_afe_set_param_v3(int port, int module_id, + int param_id, uint32_t length, void *data) +{ + struct afe_port_cmd_set_param_v3 *set_param = NULL; + uint32_t set_param_size = sizeof(struct afe_port_cmd_set_param_v3); + struct param_hdr_v3 param_hdr; + u16 port_id = 0; + int index = 0; + u8 *packed_param_data = NULL; + int packed_data_size = sizeof(union param_hdrs) + length; + int ret = 0; + + pr_info("%s: port=0x%x, module=0x%x, param_id=0x%x, size=%d\n", + __func__, port, module_id, param_id, length); + + port_id = q6audio_get_port_id(port); + ret = q6audio_validate_port(port_id); + if (ret < 0) { + pr_err("%s: Not a valid port id = 0x%x ret %d\n", __func__, + port_id, ret); + return -EINVAL; + } + index = q6audio_get_port_index(port); + + memset(¶m_hdr, 0, sizeof(param_hdr)); + param_hdr.module_id = module_id; + param_hdr.instance_id = INSTANCE_ID_0; + param_hdr.param_id = param_id; + param_hdr.param_size = length; + pr_debug("CRUS: param_size %d\n", length); + + packed_param_data = kzalloc(packed_data_size, GFP_KERNEL); + if (packed_param_data == NULL) + return -ENOMEM; + + ret = q6common_pack_pp_params(packed_param_data, ¶m_hdr, (u8 *)data, + &packed_data_size); + if (ret) { + pr_err("%s: Failed to pack param header and data, error %d\n", + __func__, ret); + goto fail_cmd; + } + + set_param_size += packed_data_size; + set_param = kzalloc(set_param_size, GFP_KERNEL); + if (set_param == NULL) { + ret = -ENOMEM; + goto fail_cmd; + } + + set_param->apr_hdr.hdr_field = + APR_HDR_FIELD(APR_MSG_TYPE_SEQ_CMD, APR_HDR_LEN(APR_HDR_SIZE), + APR_PKT_VER); + set_param->apr_hdr.pkt_size = sizeof(struct afe_port_cmd_set_param_v3) + + packed_data_size; + set_param->apr_hdr.src_port = 0; + set_param->apr_hdr.dest_port = 0; + set_param->apr_hdr.token = index; + set_param->apr_hdr.opcode = AFE_PORT_CMD_SET_PARAM_V3; + set_param->port_id = port_id; + set_param->payload_size = packed_data_size; + memcpy(&set_param->param_data, packed_param_data, + packed_data_size); + + atomic_set(cspl_afe.state, 1); + //atomic_set(&this_ctrl.callback_wait, 0); + ret = apr_send_pkt(*cspl_afe.apr, (uint32_t *) set_param); + if (ret < 0) { + pr_err("%s: Setting param for port %d param[0x%x]failed\n", + __func__, port, param_id); + goto fail_cmd; + } + + ret = wait_event_timeout(cspl_afe.wait[index], + (atomic_read(cspl_afe.state) == 0), + msecs_to_jiffies(cspl_afe.timeout_ms*10)); + + if (!ret) { + pr_err("%s: wait_event timeout\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + + if (atomic_read(cspl_afe.status) != 0) { + pr_err("%s: set param cmd failed\n", __func__); + ret = -EINVAL; + goto fail_cmd; + } + + ret = 0; +fail_cmd: + pr_info("[CSPL]%s param_id %x status %d\n", __func__, param_id, ret); + kfree(set_param); + kfree(packed_param_data); + return ret; +} + +static int crus_afe_send_config(const char *data, int32_t length, + int32_t port, int32_t module) +{ + struct afe_custom_crus_set_config_v2_t *config = NULL; + struct crus_external_config_t *payload = NULL; + int size = sizeof(struct crus_external_config_t); + int chars_to_send, mem_size, sent = 0, ret = 0; + int index = afe_get_port_index(port); + uint32_t param = 0; + + pr_info("CRUS_SP: (send_config) module = 0x%08x, port = 0x%08x\n", + module, port); + + /* Destination settings for message */ + if (port == this_ctrl.ff_port) + param = CRUS_PARAM_RX_SET_EXT_CONFIG; + else if (port == this_ctrl.fb_port) + param = CRUS_PARAM_TX_SET_EXT_CONFIG; + else { + pr_err("CRUS_SP: Received invalid port parameter %d\n", port); + return -EINVAL; + } + + if (length > APR_CHUNK_SIZE) + mem_size = APR_CHUNK_SIZE; + else + mem_size = length; + + config = crus_gen_afe_set_header(size, port, module, param); + if (config == NULL) { + pr_err("CRUS_SP: Memory allocation failed\n"); + return -ENOMEM; + } + + payload = (struct crus_external_config_t *)((u8 *)config + + sizeof(struct afe_custom_crus_set_config_v2_t)); + payload->total_size = (uint32_t)length; + payload->reserved = 0; + payload->config = PAYLOAD_FOLLOWS_CONFIG; + /* ^ This tells the algorithm to expect array */ + /* immediately following the header */ + + /* Send config string in chunks of APR_CHUNK_SIZE bytes */ + while (sent < length) { + chars_to_send = length - sent; + if (chars_to_send > APR_CHUNK_SIZE) { + chars_to_send = APR_CHUNK_SIZE; + payload->done = 0; + } else { + payload->done = 1; + } + + /* Configure per message parameter settings */ + memcpy(payload->data, data + sent, chars_to_send); + payload->chunk_size = chars_to_send; + + /* Send the actual message */ + ret = afe_apr_send_pkt_crus(config, index, 1); + + if (ret) { + pr_err("CRUS_SP: (send_config) failure code %d\n", ret); + break; + } + + sent += chars_to_send; + } + + kfree(config); + return ret; +} + + +static int crus_afe_send_delta(const char *data, uint32_t length) +{ + struct afe_custom_crus_set_config_t *config = NULL; + struct crus_delta_config_t *payload = NULL; + int size = sizeof(struct crus_delta_config_t); + int port = this_ctrl.ff_port; + int param = CRUS_PARAM_RX_SET_DELTA_CONFIG; + int module = CIRRUS_SP; + int chars_to_send, mem_size, sent = 0, ret = 0; + int index = afe_get_port_index(port); + + pr_info("CRUS_SP: (send_delta) module = 0x%08x, port = 0x%08x\n", + module, port); + + if (length > APR_CHUNK_SIZE) + mem_size = APR_CHUNK_SIZE; + else + mem_size = length; + + config = crus_gen_afe_set_header(size, port, module, param); + if (config == NULL) { + pr_err("CRUS_SP: Memory allocation failed\n"); + return -ENOMEM; + } + + payload = (struct crus_delta_config_t *)((u8 *)config + + sizeof(struct afe_custom_crus_set_config_t)); + payload->total_size = length; + payload->index = 0; + payload->reserved = 0; + payload->config = PAYLOAD_FOLLOWS_CONFIG; + /* ^ This tells the algorithm to expect array */ + /* immediately following the header */ + + /* Send config string in chunks of APR_CHUNK_SIZE bytes */ + while (sent < length) { + chars_to_send = length - sent; + if (chars_to_send > APR_CHUNK_SIZE) { + chars_to_send = APR_CHUNK_SIZE; + payload->done = 0; + } else + payload->done = 1; + + /* Configure per message parameter settings */ + memcpy(payload->data, data + sent, chars_to_send); + payload->chunk_size = chars_to_send; + + /* Send the actual message */ + ret = afe_apr_send_pkt_crus(config, index, 1); + + if (ret) { + pr_err("CRUS_SP: (send_delta) failure code %d\n", ret); + break; + } + + sent += chars_to_send; + } + + kfree(config); + return ret; +} + +extern int crus_afe_callback(void* payload, int size) +{ + uint32_t* payload32 = payload; + + pr_debug("%s: module=0x%x size = %d\n", + __func__, (int)payload32[1], size); + + switch(payload32[1]) { + case CIRRUS_SP: + memcpy(this_ctrl.user_buffer, payload32, size); + atomic_set(&this_ctrl.callback_wait, 1); + break; + default: + return -EINVAL; + } + + return 0; +} + + + +int msm_routing_cirrus_fbport_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + this_ctrl.fb_port_index = ucontrol->value.integer.value[0]; + pr_info("%s: %d\n", __func__, this_ctrl.fb_port); + + switch (this_ctrl.fb_port_index) { + case 0: + this_ctrl.fb_port = AFE_PORT_ID_PRIMARY_MI2S_TX; + this_ctrl.ff_port = AFE_PORT_ID_PRIMARY_MI2S_RX; + break; + case 1: + this_ctrl.fb_port = AFE_PORT_ID_SECONDARY_MI2S_TX; + this_ctrl.ff_port = AFE_PORT_ID_SECONDARY_MI2S_RX; + break; + case 2: + this_ctrl.fb_port = AFE_PORT_ID_TERTIARY_MI2S_TX; + this_ctrl.ff_port = AFE_PORT_ID_TERTIARY_MI2S_RX; + break; + case 3: + this_ctrl.fb_port = AFE_PORT_ID_QUATERNARY_MI2S_TX; + this_ctrl.ff_port = AFE_PORT_ID_QUATERNARY_MI2S_RX; + break; + default: + /* Default port to QUATERNARY */ + this_ctrl.fb_port = AFE_PORT_ID_QUATERNARY_MI2S_TX; + this_ctrl.ff_port = AFE_PORT_ID_QUATERNARY_MI2S_RX; + break; + } + return 0; +} + +int msm_routing_cirrus_fbport_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: this_ctrl.fb_port = %d", __func__, this_ctrl.fb_port); + ucontrol->value.integer.value[0] = this_ctrl.fb_port_index; + return 0; +} + +static int msm_routing_crus_sp_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + const int crus_set = ucontrol->value.integer.value[0]; + + + this_ctrl.enable = crus_set; + + return 0; +} + +static int msm_routing_crus_sp_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: %d\n", __func__, this_ctrl.enable); + ucontrol->value.integer.value[0] = this_ctrl.enable; + + return 0; +} +static int msm_routing_crus_sp_prot_enable_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_err("CRUS_SP: Cirrus SP Protection Enable is set via DT\n"); + return 0; +} + +static int msm_routing_crus_sp_prot_enable_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = this_ctrl.prot_en ? 1 : 0; + return 0; +} + +static int msm_routing_crus_sp_usecase_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct crus_rx_run_case_ctrl_t case_ctrl; + struct crus_rx_temperature_t rx_temp; + const int crus_set = ucontrol->value.integer.value[0]; + //struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + //uint32_t max_index = e->items; + int buffer[CRUS_MAX_BUFFER_SIZE / 4]; + + if (crus_set >= 4) { + pr_err("CRUS_SP: Config index out of bounds (%d)\n", crus_set); + return -EINVAL; + } + + if(this_ctrl.q6afe_rev == 2) + crus_afe_get_param(this_ctrl.ff_port, CIRRUS_SP, CRUS_PARAM_RX_GET_TEMP, + CRUS_MAX_BUFFER_SIZE, buffer); + else + crus_afe_get_param_v3(this_ctrl.ff_port, CIRRUS_SP, CRUS_PARAM_RX_GET_TEMP, + CRUS_MAX_BUFFER_SIZE, buffer); + + memcpy(&rx_temp, buffer, sizeof(rx_temp)); + + this_ctrl.usecase = crus_set; + + case_ctrl.status_l = 1; + case_ctrl.status_r = 1; + case_ctrl.z_l = rx_temp.z_l; + case_ctrl.z_r = rx_temp.z_r; + case_ctrl.checksum_l = rx_temp.z_l + 1; + case_ctrl.checksum_r = rx_temp.z_r + 1; + case_ctrl.atemp = rx_temp.amb_temp_l; + case_ctrl.value = this_ctrl.usecase; + + if (this_ctrl.prot_en) { + if(this_ctrl.q6afe_rev == 2) { + crus_afe_set_param(this_ctrl.fb_port, CIRRUS_SP, + CRUS_PARAM_TX_SET_USECASE, + sizeof(this_ctrl.usecase), + (void *)&this_ctrl.usecase); + } else { + crus_afe_set_param_v3(this_ctrl.fb_port, CIRRUS_SP, + CRUS_PARAM_TX_SET_USECASE, + sizeof(this_ctrl.usecase), + (void *)&this_ctrl.usecase); + } + } + + + + if(this_ctrl.q6afe_rev == 2) { + crus_afe_set_param(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_SET_USECASE, sizeof(case_ctrl), + (void *)&case_ctrl); + } else { + crus_afe_set_param_v3(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_SET_USECASE, sizeof(case_ctrl), + (void *)&case_ctrl); + } + + return 0; +} + +static int msm_routing_crus_sp_usecase_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_info("%s: %d\n", __func__, this_ctrl.usecase); + ucontrol->value.integer.value[0] = this_ctrl.usecase; + + return 0; +} + +static int msm_routing_crus_load_config_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *plat = snd_soc_kcontrol_platform(kcontrol); + const int crus_set = ucontrol->value.integer.value[0]; + char config[CONFIG_FILE_SIZE]; + const struct firmware *firmware; + + pr_debug("%s: %d\n", __func__, crus_set); + this_ctrl.conf_sel = crus_set; + + switch (crus_set) { + case 0: /* "None" */ + break; + case 1: /* Load RX Config */ + snprintf(config, CONFIG_FILE_SIZE, CRUS_RX_CONFIG, + this_ctrl.usecase); + + if (request_firmware(&firmware, config, plat->dev) != 0) { + pr_err("CRUS_SP: Request firmware failed\n"); + return -EINVAL; + } + + pr_info("CRUS_SP: Sending RX config...\n"); + + crus_afe_send_config(firmware->data, firmware->size, + this_ctrl.ff_port, CIRRUS_SP); + release_firmware(firmware); + break; + case 2: /* Load TX Config */ + if (this_ctrl.prot_en == false) + return -EINVAL; + + snprintf(config, CONFIG_FILE_SIZE, CRUS_TX_CONFIG, + this_ctrl.usecase); + + if (request_firmware(&firmware, config, plat->dev) != 0) { + pr_err("CRUS_SP: Request firmware failed\n"); + return -EINVAL; + } + + pr_info("CRUS_SP: Sending TX config...\n"); + + crus_afe_send_config(firmware->data, firmware->size, + this_ctrl.fb_port, CIRRUS_SP); + release_firmware(firmware); + break; + default: + return -EINVAL; + } + + this_ctrl.conf_sel = 0; + + return 0; +} + +static int msm_routing_crus_load_config_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: %d\n", __func__, this_ctrl.conf_sel); + ucontrol->value.integer.value[0] = this_ctrl.conf_sel; + return 0; +} + +static int msm_routing_crus_delta_config_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_platform *plat = snd_soc_kcontrol_platform(kcontrol); + struct crus_single_data_t data; + const int crus_set = ucontrol->value.integer.value[0]; + const struct firmware *firmware; + + switch (crus_set) { + case 0: + break; + case 1: /* Load delta config over AFE */ + this_ctrl.delta_sel = crus_set; + + if (request_firmware(&firmware, "crus_sp_delta_config.bin", + plat->dev) != 0) { + pr_err("CRUS_SP: Request firmware failed\n"); + this_ctrl.delta_sel = 0; + return -EINVAL; + } + + pr_info("CRUS_SP: Sending delta config...\n"); + + crus_afe_send_delta(firmware->data, firmware->size); + release_firmware(firmware); + break; + case 2: /* Run delta transition */ + this_ctrl.delta_sel = crus_set; + data.value = 0; + crus_afe_set_param(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_RUN_DELTA_CONFIG, + sizeof(struct crus_single_data_t), &data); + break; + default: + return -EINVAL; + } + + this_ctrl.delta_sel = 0; + return 0; +} + +static int msm_routing_crus_delta_config_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + ucontrol->value.integer.value[0] = this_ctrl.delta_sel; + return 0; +} + +static int msm_routing_crus_vol_attn_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + const int crus_set = ucontrol->value.integer.value[0]; + struct crus_dual_data_t data; + + mutex_lock(&this_ctrl.sp_lock); + + this_ctrl.vol_atten = crus_set; + + switch (crus_set) { + case 0: /* 0dB */ + data.data1 = VOL_ATTN_MAX; + data.data2 = VOL_ATTN_MAX; + break; + case 1: /* -18dB */ + data.data1 = VOL_ATTN_18DB; + data.data2 = VOL_ATTN_18DB; + break; + case 2: /* -24dB */ + data.data1 = VOL_ATTN_24DB; + data.data2 = VOL_ATTN_24DB; + break; + default: + return -EINVAL; + } + + if(this_ctrl.q6afe_rev == 2) { + crus_afe_set_param(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_SET_ATTENUATION, + sizeof(struct crus_dual_data_t), &data); + } else { + crus_afe_set_param_v3(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_SET_ATTENUATION, + sizeof(struct crus_dual_data_t), &data); + } + + mutex_unlock(&this_ctrl.sp_lock); + + return 0; +} + +static int msm_routing_crus_vol_attn_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("Starting Cirrus SP Volume Attenuation Get function call\n"); + ucontrol->value.integer.value[0] = this_ctrl.vol_atten; + + return 0; +} + + +static int msm_routing_crus_chan_swap_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct crus_dual_data_t data; + const int crus_set = ucontrol->value.integer.value[0]; + + switch (crus_set) { + case 0: /* L/R */ + data.data1 = 1; + break; + case 1: /* R/L */ + data.data1 = 2; + break; + default: + return -EINVAL; + } + + data.data2 = this_ctrl.ch_sw_duration; + + mutex_lock(&this_ctrl.sp_lock); + + this_ctrl.ch_sw = crus_set; + + if(this_ctrl.q6afe_rev == 2) + crus_afe_set_param(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_CHANNEL_SWAP, + sizeof(struct crus_dual_data_t), &data); + else + crus_afe_set_param_v3(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_CHANNEL_SWAP, + sizeof(struct crus_dual_data_t), &data); + + mutex_unlock(&this_ctrl.sp_lock); + + return 0; +} + +static int msm_routing_crus_chan_swap_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct crus_single_data_t data; + pr_debug("%s: %d\n", __func__, this_ctrl.ch_sw); + crus_afe_get_param(this_ctrl.ff_port, CIRRUS_SP, + CRUS_PARAM_RX_GET_CHANNEL_SWAP, + sizeof(struct crus_single_data_t), &data); + + ucontrol->value.integer.value[0] = this_ctrl.ch_sw; + + return 0; +} + +static int msm_routing_crus_chan_swap_dur_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int crus_set = ucontrol->value.integer.value[0]; + + pr_debug("%s: %d\n", __func__, crus_set); + + if ((crus_set < 0) || (crus_set > MAX_CHAN_SWAP_SAMPLES)) { + pr_err("CRUS_SP: Value out of range (%d)\n", crus_set); + return -EINVAL; + } + + if (crus_set < MIN_CHAN_SWAP_SAMPLES) { + pr_info("CRUS_SP: Received %d, round up to min value %d\n", + crus_set, MIN_CHAN_SWAP_SAMPLES); + crus_set = MIN_CHAN_SWAP_SAMPLES; + } + + this_ctrl.ch_sw_duration = crus_set; + + return 0; +} + +static int msm_routing_crus_chan_swap_dur_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + pr_debug("%s: %d\n", __func__, this_ctrl.ch_sw_duration); + + ucontrol->value.integer.value[0] = this_ctrl.ch_sw_duration; + + return 0; +} +static int msm_routing_crus_fail_det(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static int msm_routing_crus_fail_det_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + return 0; +} + +static const char * const cirrus_fb_port_text[] = {"PRI_MI2S_RX", + "SEC_MI2S_RX", + "TERT_MI2S_RX", + "QUAT_MI2S_RX", + "QUAT_TDM_RX_0", + "SLIMBUS_0_RX"}; + +static const char * const crus_en_text[] = {"Config SP Disable", + "Config SP Enable"}; + +static const char * const crus_prot_en_text[] = {"Disable", "Enable"}; + +static const char * const crus_conf_load_text[] = {"Idle", "Load RX", + "Load TX"}; + +static const char * const crus_conf_load_no_prot_text[] = {"Idle", "Load"}; + +static const char * const crus_delta_text[] = {"Idle", "Load", "Run"}; + +static const char * const crus_chan_swap_text[] = {"LR", "RL"}; +static const char * crus_sp_usecase_dt_text[MAX_TUNING_CONFIGS] = {"Music", "Voice", "Headset", "Handsfree"}; + +static const char * const crus_vol_attn_text[] = {"0dB", "-18dB", "-24dB"}; + + +static const struct soc_enum cirrus_fb_controls_enum[] = { + SOC_ENUM_SINGLE_EXT(6, cirrus_fb_port_text), +}; + +static const struct soc_enum crus_en_enum[] = { + SOC_ENUM_SINGLE_EXT(2, crus_en_text), +}; + +static const struct soc_enum crus_prot_en_enum[] = { + SOC_ENUM_SINGLE_EXT(2, crus_prot_en_text), +}; + +static struct soc_enum crus_sp_usecase_enum[] = { + SOC_ENUM_SINGLE_EXT(MAX_TUNING_CONFIGS, crus_sp_usecase_dt_text), +}; + +static const struct soc_enum crus_conf_load_enum[] = { + SOC_ENUM_SINGLE_EXT(3, crus_conf_load_text), +}; + +static const struct soc_enum crus_conf_load_no_prot_enum[] = { + SOC_ENUM_SINGLE_EXT(2, crus_conf_load_no_prot_text), +}; + +static const struct soc_enum crus_delta_enum[] = { + SOC_ENUM_SINGLE_EXT(3, crus_delta_text), +}; + +static const struct soc_enum crus_chan_swap_enum[] = { + SOC_ENUM_SINGLE_EXT(2, crus_chan_swap_text), +}; + +static const struct soc_enum crus_vol_attn_enum[] = { + SOC_ENUM_SINGLE_EXT(3, crus_vol_attn_text), +}; +static const struct snd_kcontrol_new crus_protect_controls[] = { + SOC_ENUM_EXT("Cirrus SP FBPort", cirrus_fb_controls_enum[0], + msm_routing_cirrus_fbport_get, msm_routing_cirrus_fbport_put), + SOC_ENUM_EXT("Cirrus SP", crus_en_enum[0], + msm_routing_crus_sp_enable_get, msm_routing_crus_sp_enable_put), + SOC_ENUM_EXT("Cirrus SP Protection", crus_prot_en_enum[0], + msm_routing_crus_sp_prot_enable_get, msm_routing_crus_sp_prot_enable_put), + SOC_ENUM_EXT("Cirrus SP Usecase", crus_sp_usecase_enum[0], + msm_routing_crus_sp_usecase_get, msm_routing_crus_sp_usecase_put), + SOC_ENUM_EXT("Cirrus SP Load Config", crus_conf_load_enum[0], + msm_routing_crus_load_config_get, msm_routing_crus_load_config_put), + SOC_ENUM_EXT("Cirrus SP Delta Config", crus_delta_enum[0], + msm_routing_crus_delta_config_get, msm_routing_crus_delta_config_put), + SOC_ENUM_EXT("Cirrus SP Channel Swap", crus_chan_swap_enum[0], + msm_routing_crus_chan_swap_get, msm_routing_crus_chan_swap_put), + SOC_SINGLE_EXT("Cirrus SP Channel Swap Duration", SND_SOC_NOPM, 0, + MAX_CHAN_SWAP_SAMPLES, 0, msm_routing_crus_chan_swap_dur_get, + msm_routing_crus_chan_swap_dur_put), + SOC_SINGLE_BOOL_EXT("Cirrus SP Failure Detection", 0, + msm_routing_crus_fail_det_get, msm_routing_crus_fail_det), +}; +static const struct snd_kcontrol_new crus_no_protect_controls[] = { + SOC_ENUM_EXT("Cirrus SP FBPort", cirrus_fb_controls_enum[0], + msm_routing_cirrus_fbport_get, msm_routing_cirrus_fbport_put), + SOC_ENUM_EXT("Cirrus SP", crus_en_enum[0], + msm_routing_crus_sp_enable_get, msm_routing_crus_sp_enable_put), + SOC_ENUM_EXT("Cirrus SP Protection", crus_prot_en_enum[0], + msm_routing_crus_sp_prot_enable_get, msm_routing_crus_sp_prot_enable_put), + SOC_ENUM_EXT("Cirrus SP Usecase", crus_sp_usecase_enum[0], + msm_routing_crus_sp_usecase_get, msm_routing_crus_sp_usecase_put), + SOC_ENUM_EXT("Cirrus SP Load Config", crus_conf_load_no_prot_enum[0], + msm_routing_crus_load_config_get, msm_routing_crus_load_config_put), + SOC_ENUM_EXT("Cirrus SP Delta Config", crus_delta_enum[0], + msm_routing_crus_delta_config_get, msm_routing_crus_delta_config_put), + SOC_ENUM_EXT("Cirrus SP Channel Swap", crus_chan_swap_enum[0], + msm_routing_crus_chan_swap_get, msm_routing_crus_chan_swap_put), + SOC_SINGLE_EXT("Cirrus SP Channel Swap Duration", SND_SOC_NOPM, 0, + MAX_CHAN_SWAP_SAMPLES, 0, msm_routing_crus_chan_swap_dur_get, + msm_routing_crus_chan_swap_dur_put), + SOC_ENUM_EXT("Cirrus SP Volume Attenuation", crus_vol_attn_enum[0], + msm_routing_crus_vol_attn_get, msm_routing_crus_vol_attn_put), +}; + +void msm_crus_pb_add_controls(struct snd_soc_platform *platform) +{ + if (this_ctrl.usecase_dt_count == 0) + pr_info("CRUS_SP: Usecase config not specified\n"); + + crus_sp_usecase_enum[0].items = this_ctrl.usecase_dt_count; + crus_sp_usecase_enum[0].texts = crus_sp_usecase_dt_text; + + if (this_ctrl.prot_en) + snd_soc_add_platform_controls(platform, crus_protect_controls, + ARRAY_SIZE(crus_protect_controls)); + else + snd_soc_add_platform_controls(platform, + crus_no_protect_controls, + ARRAY_SIZE(crus_no_protect_controls)); +} + +EXPORT_SYMBOL(msm_crus_pb_add_controls); +int crus_afe_port_start(u16 port_id) +{ + pr_info("%s: 0x%x\n", __func__, port_id); + +//CSPL do not be involved in AFE +#if 0 + struct snd_kcontrol kcontrol; + struct snd_ctl_elem_value ucontrol; + + if (port_id != this_ctrl.ff_port) + return 0; + + this_ctrl.afe_start = true; + pr_info("%s: 0x%x\n", __func__, port_id); + + mutex_lock(&this_ctrl.sp_lock); + msm_routing_crus_sp_usecase_get(&kcontrol, + &ucontrol); + msm_routing_crus_sp_usecase_put(&kcontrol, + &ucontrol); + mutex_unlock(&this_ctrl.sp_lock); +#endif + return 0; +} +EXPORT_SYMBOL(crus_afe_port_start); +int crus_afe_port_close(u16 port_id) +{ + pr_info("%s: 0x%x\n", __func__, port_id); + +//CSPL do not be involved in AFE +#if 0 + if (port_id != this_ctrl.ff_port) + return 0; + + this_ctrl.afe_start = false; + pr_info("%s: 0x%x\n", __func__, port_id); +#endif + return 0; +} +EXPORT_SYMBOL(crus_afe_port_close); +static long crus_sp_shared_ioctl(struct file *f, unsigned int cmd, + void __user *arg) +{ + int result = 0, port; + uint32_t bufsize = 0, size; + void *io_data = NULL; + + pr_info("%s\n", __func__); + + if (copy_from_user(&size, arg, sizeof(size))) { + pr_err("CRUS_SP: copy_from_user (size) failed\n"); + result = -EFAULT; + goto exit; + } + + /* Copy IOCTL header from usermode */ + if (copy_from_user(&crus_sp_hdr, arg, size)) { + pr_err("CRUS_SP: copy_from_user (struct) failed\n"); + result = -EFAULT; + goto exit; + } + + bufsize = crus_sp_hdr.data_length; + io_data = kzalloc(bufsize, GFP_KERNEL); + + switch (cmd) { + case CRUS_SP_IOCTL_GET: + switch (crus_sp_hdr.module_id) { + case CRUS_MODULE_ID_TX: + port = this_ctrl.fb_port; + break; + case CRUS_MODULE_ID_RX: + port = this_ctrl.ff_port; + break; + default: + pr_info("CRUS_SP: Unrecognized port ID (%d)\n", + crus_sp_hdr.module_id); + port = this_ctrl.ff_port; + } + if(this_ctrl.q6afe_rev == 2) + crus_afe_get_param(port, CIRRUS_SP, crus_sp_hdr.param_id, + bufsize, io_data); + else + crus_afe_get_param_v3(port, CIRRUS_SP, crus_sp_hdr.param_id, + bufsize, io_data); + result = copy_to_user(crus_sp_hdr.data, io_data, bufsize); + if (result) { + pr_err("CRUS_SP: copy_to_user failed (%d)\n", result); + result = -EFAULT; + } else + result = bufsize; + break; + case CRUS_SP_IOCTL_SET: + result = copy_from_user(io_data, (void *)crus_sp_hdr.data, + bufsize); + if (result) { + pr_err("CRUS_SP: copy_from_user failed (%d)\n", result); + result = -EFAULT; + goto exit_io; + } + + switch (crus_sp_hdr.module_id) { + case CRUS_MODULE_ID_TX: + port = this_ctrl.fb_port; + break; + case CRUS_MODULE_ID_RX: + port = this_ctrl.ff_port; + break; + default: + pr_info("%s: Unrecognized port ID (%d)\n", __func__, + crus_sp_hdr.module_id); + port = this_ctrl.ff_port; + } + + if(this_ctrl.q6afe_rev == 2) { + crus_afe_set_param(port, CIRRUS_SP, + crus_sp_hdr.param_id, bufsize, io_data); + } else { + crus_afe_set_param_v3(port, CIRRUS_SP, + crus_sp_hdr.param_id, bufsize, io_data); + } + break; + + default: + pr_err("CRUS_SP: Invalid IOCTL, command = %d\n", cmd); + result = -EINVAL; + break; + } + +exit_io: + kfree(io_data); +exit: + return result; +} + +static long crus_sp_ioctl(struct file *f, + unsigned int cmd, unsigned long arg) +{ + pr_info("%s\n", __func__); + + return crus_sp_shared_ioctl(f, cmd, (void __user *)arg); +} + +static long crus_sp_compat_ioctl(struct file *f, + unsigned int cmd, unsigned long arg) +{ + unsigned int cmd64; + + pr_info("%s\n", __func__); + + switch (cmd) { + case CRUS_SP_IOCTL_GET32: + cmd64 = CRUS_SP_IOCTL_GET; + break; + case CRUS_SP_IOCTL_SET32: + cmd64 = CRUS_SP_IOCTL_SET; + break; + default: + pr_err("CRUS_SP: Invalid IOCTL, command = %d\n", cmd); + return -EINVAL; + } + + return crus_sp_shared_ioctl(f, cmd64, compat_ptr(arg)); +} + +static int crus_sp_open(struct inode *inode, struct file *f) +{ + pr_debug("%s\n", __func__); + + atomic_inc(&this_ctrl.count_wait); + return 0; +} + +static int crus_sp_release(struct inode *inode, struct file *f) +{ + atomic_dec(&this_ctrl.count_wait); + return 0; +} + +static ssize_t temperature_left_show(struct device *dev, + struct device_attribute *a, char *buf) +{ + struct crus_rx_temperature_t rx_temp; + static const int material = 250; + static const int scale_factor = 100000; + int buffer[CRUS_MAX_BUFFER_SIZE / 4]; + int out_cal0; + int out_cal1; + int z, r, t; + int temp0; + + crus_afe_get_param(this_ctrl.ff_port, CIRRUS_SP, CRUS_PARAM_RX_GET_TEMP, + CRUS_MAX_BUFFER_SIZE, buffer); + + memcpy(&rx_temp, buffer, sizeof(rx_temp)); + + out_cal0 = rx_temp.hp_status_l; + out_cal1 = rx_temp.full_status_l; + + z = rx_temp.z_l; + + temp0 = rx_temp.amb_temp_l; + + if ((out_cal0 != 2) || (out_cal1 != 2)) + return snprintf(buf, PAGE_SIZE, "Calibration is not done\n"); + + r = rx_temp.temp_l; + t = (material * scale_factor * (r-z) / z) + (temp0 * scale_factor); + + return snprintf(buf, PAGE_SIZE, "%d.%05dc\n", t / scale_factor, + t % scale_factor); +} +static DEVICE_ATTR_RO(temperature_left); + +static ssize_t temperature_right_show(struct device *dev, + struct device_attribute *a, char *buf) +{ + struct crus_rx_temperature_t rx_temp; + static const int material = 250; + static const int scale_factor = 100000; + int buffer[CRUS_MAX_BUFFER_SIZE / 4]; + int out_cal0; + int out_cal1; + int z, r, t; + int temp0; + + crus_afe_get_param(this_ctrl.ff_port, CIRRUS_SP, CRUS_PARAM_RX_GET_TEMP, + CRUS_MAX_BUFFER_SIZE, buffer); + + memcpy(&rx_temp, buffer, sizeof(rx_temp)); + + out_cal0 = rx_temp.hp_status_r; + out_cal1 = rx_temp.full_status_r; + + z = rx_temp.z_r; + + temp0 = rx_temp.amb_temp_r; + + if ((out_cal0 != 2) || (out_cal1 != 2)) + return snprintf(buf, PAGE_SIZE, "Calibration is not done\n"); + + r = rx_temp.temp_r; + t = (material * scale_factor * (r-z) / z) + (temp0 * scale_factor); + + return snprintf(buf, PAGE_SIZE, "%d.%05dc\n", t / scale_factor, + t % scale_factor); +} +static DEVICE_ATTR_RO(temperature_right); + +static ssize_t resistance_left_show(struct device *dev, + struct device_attribute *a, char *buf) +{ + struct crus_rx_temperature_t rx_temp; + static const int scale_factor = 100000000; + static const int amp_factor = 71498; + int buffer[CRUS_MAX_BUFFER_SIZE / 4]; + int out_cal0; + int out_cal1; + int r; + + crus_afe_get_param(this_ctrl.ff_port, CIRRUS_SP, CRUS_PARAM_RX_GET_TEMP, + CRUS_MAX_BUFFER_SIZE, buffer); + + memcpy(&rx_temp, buffer, sizeof(rx_temp)); + + out_cal0 = rx_temp.hp_status_l; + out_cal1 = rx_temp.full_status_l; + + if ((out_cal0 != 2) || (out_cal1 != 2)) + return snprintf(buf, PAGE_SIZE, "Calibration is not done\n"); + + r = rx_temp.temp_l * amp_factor; + + return snprintf(buf, PAGE_SIZE, "%d.%08d ohms\n", r / scale_factor, + r % scale_factor); +} +static DEVICE_ATTR_RO(resistance_left); + +static ssize_t resistance_right_show(struct device *dev, + struct device_attribute *a, char *buf) +{ + struct crus_rx_temperature_t rx_temp; + static const int scale_factor = 100000000; + static const int amp_factor = 71498; + int buffer[CRUS_MAX_BUFFER_SIZE / 4]; + int out_cal0; + int out_cal1; + int r; + + crus_afe_get_param(this_ctrl.ff_port, CIRRUS_SP, CRUS_PARAM_RX_GET_TEMP, + CRUS_MAX_BUFFER_SIZE, buffer); + + memcpy(&rx_temp, buffer, sizeof(rx_temp)); + + out_cal0 = rx_temp.hp_status_r; + out_cal1 = rx_temp.full_status_r; + + if ((out_cal0 != 2) || (out_cal1 != 2)) + return snprintf(buf, PAGE_SIZE, "Calibration is not done\n"); + + r = rx_temp.temp_r * amp_factor; + + return snprintf(buf, PAGE_SIZE, "%d.%08d ohms\n", r / scale_factor, + r % scale_factor); +} +static DEVICE_ATTR_RO(resistance_right); + +static struct attribute *crus_sp_attrs[] = { + &dev_attr_temperature_left.attr, + &dev_attr_temperature_right.attr, + &dev_attr_resistance_left.attr, + &dev_attr_resistance_right.attr, + NULL, +}; + +static const struct attribute_group crus_sp_group = { + .attrs = crus_sp_attrs, +}; + +static const struct attribute_group *crus_sp_groups[] = { + &crus_sp_group, + NULL, +}; + +#ifdef CONFIG_OF +static int msm_cirrus_playback_probe(struct platform_device *pdev) +{ + int i; + + pr_info("CRUS_SP: Initializing platform device\n"); + + this_ctrl.usecase_dt_count = of_property_count_strings(pdev->dev.of_node, + "usecase-names"); + if (this_ctrl.usecase_dt_count <= 0) { + pr_debug("CRUS_SP: Usecase names not found\n"); + this_ctrl.usecase_dt_count = 0; + return 0; + } + + if ((this_ctrl.usecase_dt_count > 0) && + (this_ctrl.usecase_dt_count <= MAX_TUNING_CONFIGS)) + of_property_read_string_array(pdev->dev.of_node, + "usecase-names", + crus_sp_usecase_dt_text, + this_ctrl.usecase_dt_count); + else if (this_ctrl.usecase_dt_count > MAX_TUNING_CONFIGS) { + pr_err("CRUS_SP: Max of %d usecase configs allowed\n", + MAX_TUNING_CONFIGS); + return -EINVAL; + } + + for (i = 0; i < this_ctrl.usecase_dt_count; i++) + pr_info("CRUS_SP: Usecase[%d] = %s\n", i, + crus_sp_usecase_dt_text[i]); + + this_ctrl.prot_en = of_property_read_bool(pdev->dev.of_node, + "protect-en"); + + return 0; +} + +static const struct of_device_id msm_cirrus_playback_dt_match[] = { + {.compatible = "cirrus,msm-cirrus-playback"}, + {} +}; +MODULE_DEVICE_TABLE(of, msm_cirrus_playback_dt_match); + +static struct platform_driver msm_cirrus_playback_driver = { + .driver = { + .name = "msm-cirrus-playback", + .owner = THIS_MODULE, + .of_match_table = msm_cirrus_playback_dt_match, + }, + .probe = msm_cirrus_playback_probe, +}; +#endif + +static const struct file_operations crus_sp_fops = { + .owner = THIS_MODULE, + .open = crus_sp_open, + .release = crus_sp_release, + .unlocked_ioctl = crus_sp_ioctl, + .compat_ioctl = crus_sp_compat_ioctl, +}; + +struct miscdevice crus_sp_misc = { + .minor = MISC_DYNAMIC_MINOR, + .name = "msm_cirrus_playback", + .fops = &crus_sp_fops, +}; + +int __init crus_sp_init(void) +{ + pr_info("Initializing misc device\n"); + atomic_set(&this_ctrl.callback_wait, 0); + atomic_set(&this_ctrl.count_wait, 0); + mutex_init(&this_ctrl.param_lock); + mutex_init(&this_ctrl.sp_lock); + + misc_register(&crus_sp_misc); + + if (sysfs_create_groups(&crus_sp_misc.this_device->kobj, + crus_sp_groups)) + pr_err("%s: Could not create sysfs groups\n", __func__); + +#ifdef CONFIG_OF + platform_driver_register(&msm_cirrus_playback_driver); +#endif + return 0; +} + +void __exit crus_sp_exit(void) +{ + pr_debug("%s\n", __func__); + mutex_destroy(&this_ctrl.param_lock); + +#ifdef CONFIG_OF + platform_driver_unregister(&msm_cirrus_playback_driver); +#endif +} + +MODULE_AUTHOR("Cirrus SP"); +MODULE_DESCRIPTION("Providing Interface to Cirrus SP"); +MODULE_LICENSE("GPL"); diff --git a/techpack/audio/dsp/q6_init.c b/techpack/audio/dsp/q6_init.c index 202955a96040..896e5da15543 100644 --- a/techpack/audio/dsp/q6_init.c +++ b/techpack/audio/dsp/q6_init.c @@ -31,14 +31,21 @@ static int __init audio_q6_init(void) msm_audio_ion_init(); audio_slimslave_init(); avtimer_init(); +#ifdef CONFIG_MSM_CSPL + crus_sp_init(); +#endif msm_mdf_init(); voice_mhi_init(); + elliptic_driver_init(); return 0; } static void __exit audio_q6_exit(void) { msm_mdf_exit(); +#ifdef CONFIG_MSM_CSPL + crus_sp_exit(); +#endif avtimer_exit(); audio_slimslave_exit(); msm_audio_ion_exit(); @@ -53,6 +60,7 @@ static void __exit audio_q6_exit(void) audio_cal_exit(); adsp_err_exit(); voice_mhi_exit(); + elliptic_driver_exit(); } module_init(audio_q6_init); diff --git a/techpack/audio/dsp/q6_init.h b/techpack/audio/dsp/q6_init.h index 5014c37a6c32..6c6ab4920ea4 100644 --- a/techpack/audio/dsp/q6_init.h +++ b/techpack/audio/dsp/q6_init.h @@ -26,10 +26,16 @@ int rtac_init(void); int msm_audio_ion_init(void); int audio_slimslave_init(void); int avtimer_init(void); + +#ifdef CONFIG_MSM_CSPL +int crus_sp_init(void); +#endif + #ifdef CONFIG_MSM_MDF int msm_mdf_init(void); void msm_mdf_exit(void); #else +int elliptic_driver_init(void); static inline int msm_mdf_init(void) { return 0; @@ -53,6 +59,10 @@ static inline void spk_params_exit(void) } #endif +#ifdef CONFIG_MSM_CSPL +void crus_sp_exit(void); +#endif + void avtimer_exit(void); void audio_slimslave_exit(void); void msm_audio_ion_exit(void); @@ -65,6 +75,7 @@ void q6asm_exit(void); void afe_exit(void); void adm_exit(void); void adsp_err_exit(void); +int elliptic_driver_exit(void); #ifdef CONFIG_VOICE_MHI int voice_mhi_init(void); diff --git a/techpack/audio/dsp/q6adm.c b/techpack/audio/dsp/q6adm.c index 559fb812e1c0..937dc618a687 100644 --- a/techpack/audio/dsp/q6adm.c +++ b/techpack/audio/dsp/q6adm.c @@ -2923,8 +2923,11 @@ int adm_open(int port_id, int path, int rate, int channel_mode, int topology, this_adm.ffecns_port_id); } - if (topology == VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY) + if (topology == VPM_TX_VOICE_SMECNS_V2_COPP_TOPOLOGY || + topology == ADM_TOPOLOGY_ID_AUDIO_RX_FVSAM) { + pr_debug("%s: set channel_mode as 1 for topology=%d\n", __func__, topology); channel_mode = 1; + } /* * Routing driver reuses the same adm for streams with the same diff --git a/techpack/audio/dsp/q6afe.c b/techpack/audio/dsp/q6afe.c index bbf7d08bf2f6..b46ad4a8b532 100644 --- a/techpack/audio/dsp/q6afe.c +++ b/techpack/audio/dsp/q6afe.c @@ -26,10 +26,15 @@ #include #include #include +#include #include #include "adsp_err.h" #include "q6afecal-hwdep.h" +#ifdef CONFIG_MSM_CSPL +#include +#endif + #define WAKELOCK_TIMEOUT 5000 enum { AFE_COMMON_RX_CAL = 0, @@ -229,6 +234,17 @@ void afe_set_spk_v_vali_flag(int v_vali_flag) this_afe.v_vali_flag = v_vali_flag; } +#ifdef CONFIG_MSM_CSPL +struct afe_cspl_state cspl_afe = { + .apr= &this_afe.apr, + .status= &this_afe.status, + .state= &this_afe.state, + .wait= this_afe.wait, + .timeout_ms= TIMEOUT_MS, +}; +EXPORT_SYMBOL(cspl_afe); +#endif + int afe_get_topology(int port_id) { int topology; @@ -563,6 +579,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) uint32_t param_id; uint32_t param_id_pos = 0; +#ifdef CONFIG_MSM_CSPL + if (crus_afe_callback(data->payload, data->payload_size) == 0) + return 0; +#endif if (!payload || (data->token >= AFE_MAX_PORTS)) { pr_err("%s: Error: size %d payload %pK token %d\n", __func__, data->payload_size, @@ -591,6 +611,10 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) av_dev_drift_afe_cb_handler(data->opcode, data->payload, data->payload_size); } else { + if (rtac_make_afe_callback(data->payload, + data->payload_size)) + return 0; + if (sp_make_afe_callback(data->opcode, data->payload, data->payload_size)) return -EINVAL; @@ -599,6 +623,11 @@ static int32_t afe_callback(struct apr_client_data *data, void *priv) wake_up(&this_afe.wait[data->token]); else return -EINVAL; + } else if (data->opcode == ULTRASOUND_OPCODE) { + if (NULL != data->payload) + elliptic_process_apr_payload(data->payload); + else + pr_err("[EXPORT_SYMBOLLUS]: payload ptr is Invalid"); } else if (data->opcode == AFE_EVENT_MBHC_DETECTION_SW_WA) { msm_aud_evt_notifier_call_chain(SWR_WAKE_IRQ_EVENT, NULL); } else if (data->opcode == @@ -1012,6 +1041,21 @@ static int afe_apr_send_pkt(void *data, wait_queue_head_t *wait) return ret; } +#ifdef CONFIG_MSM_CSPL +int afe_apr_send_pkt_crus(void *data, int index, int set) +{ + pr_info("[CSPL] %s: index = %d, set=%d, data = %p\n", + __func__, index, set, data); + + if (set) + return afe_apr_send_pkt(data, &this_afe.wait[index]); + else /* get */ + return afe_apr_send_pkt(data, 0); +} + +EXPORT_SYMBOL(afe_apr_send_pkt_crus); +#endif + /* This function shouldn't be called directly. Instead call q6afe_set_params. */ static int q6afe_set_params_v2(u16 port_id, int index, struct mem_mapping_hdr *mem_hdr, @@ -1740,6 +1784,15 @@ static int afe_spkr_prot_reg_event_cfg(u16 port_id) return ret; } +afe_ultrasound_state_t elus_afe = { + .ptr_apr= &this_afe.apr, + .ptr_status= &this_afe.status, + .ptr_state= &this_afe.state, + .ptr_wait= this_afe.wait, + .timeout_ms= TIMEOUT_MS, +}; +EXPORT_SYMBOL(elus_afe); + static void afe_send_cal_spkr_prot_tx(int port_id) { union afe_spkr_prot_config afe_spk_config; @@ -4380,6 +4433,11 @@ static int __afe_port_start(u16 port_id, union afe_port_config *afe_config, goto fail_cmd; } ret = afe_send_cmd_port_start(port_id); +#if CONFIG_MSM_CSPL + if (ret == 0) + crus_afe_port_start(port_id); +#endif + fail_cmd: mutex_unlock(&this_afe.afe_cmd_lock); @@ -7077,6 +7135,10 @@ int afe_close(int port_id) if (ret) pr_err("%s: AFE close failed %d\n", __func__, ret); +#if CONFIG_MSM_CSPL + crus_afe_port_close(port_id); +#endif + fail_cmd: mutex_unlock(&this_afe.afe_cmd_lock); return ret; diff --git a/techpack/audio/dsp/q6audio-v2.c b/techpack/audio/dsp/q6audio-v2.c index 5a7fa6f62e09..b1556450029a 100644 --- a/techpack/audio/dsp/q6audio-v2.c +++ b/techpack/audio/dsp/q6audio-v2.c @@ -352,6 +352,8 @@ int q6audio_get_port_index(u16 port_id) return IDX_AFE_PORT_ID_RX_CODEC_DMA_RX_6; case AFE_PORT_ID_RX_CODEC_DMA_RX_7: return IDX_AFE_PORT_ID_RX_CODEC_DMA_RX_7; + case AFE_PORT_ID_PSEUDOPORT_01: + return IDX_AFE_PORT_ID_PSEUDOPORT_01; default: return -EINVAL; } } @@ -1083,6 +1085,7 @@ int q6audio_validate_port(u16 port_id) case AFE_PORT_ID_TX_CODEC_DMA_TX_5: case AFE_PORT_ID_RX_CODEC_DMA_RX_6: case AFE_PORT_ID_RX_CODEC_DMA_RX_7: + case AFE_PORT_ID_PSEUDOPORT_01: { ret = 0; break; diff --git a/techpack/audio/include/dsp/apr_audio-v2.h b/techpack/audio/include/dsp/apr_audio-v2.h index 4ff0ac873c02..3dfdcb0d8dcd 100644 --- a/techpack/audio/include/dsp/apr_audio-v2.h +++ b/techpack/audio/include/dsp/apr_audio-v2.h @@ -5075,6 +5075,7 @@ struct afe_param_id_lpass_core_shared_clk_cfg { #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_DTS_HPX 0x10015002 #define ADM_CMD_COPP_OPEN_TOPOLOGY_ID_AUDIOSPHERE 0x10028000 #define VPM_TX_DM_FLUENCE_EF_COPP_TOPOLOGY 0x10000005 +#define ADM_TOPOLOGY_ID_AUDIO_RX_FVSAM 0x1000FFF0 /* Memory map regions command payload used by the * #ASM_CMD_SHARED_MEM_MAP_REGIONS ,#ADM_CMD_SHARED_MEM_MAP_REGIONS diff --git a/techpack/audio/include/dsp/apr_elliptic.h b/techpack/audio/include/dsp/apr_elliptic.h new file mode 100755 index 000000000000..4219144b6b99 --- /dev/null +++ b/techpack/audio/include/dsp/apr_elliptic.h @@ -0,0 +1,41 @@ +#pragma once + +#include +#include +#include +#include + +#define ELLIPTIC_SET_PARAMS_SIZE 114 +#define ELLIPTIC_ULTRASOUND_MODULE_TX 0x0F010201 +#define ELLIPTIC_ULTRASOUND_MODULE_RX 0x0FF10202 +#define ULTRASOUND_OPCODE 0x0FF10204 + +/* This need to be updated for all platforms */ +#define ELLIPTIC_PORT_ID SLIMBUS_2_TX + +/** Sequence of Elliptic Labs Ultrasound module parameters */ +struct afe_ultrasound_set_params_t { + uint32_t payload[ELLIPTIC_SET_PARAMS_SIZE]; +} __packed; + +/** Sequence of Elliptic Labs Ultrasound module parameters */ + +/** Elliptic APR public */ + +int32_t ultrasound_apr_set_parameter(int32_t port_id, uint32_t param_id, + u8 *user_params, int32_t length); + +int32_t elliptic_process_apr_payload(uint32_t *payload); + +int elliptic_notify_gain_change_msg(int component_id, int gaindb); + +typedef struct afe_ultrasound_state { + atomic_t us_apr_state; + void **ptr_apr; + atomic_t *ptr_status; + atomic_t *ptr_state; + wait_queue_head_t *ptr_wait; + int timeout_ms; +} afe_ultrasound_state_t; + +extern afe_ultrasound_state_t elus_afe; diff --git a/techpack/audio/include/dsp/msm-cirrus-playback.h b/techpack/audio/include/dsp/msm-cirrus-playback.h new file mode 100644 index 000000000000..84094c8d78d8 --- /dev/null +++ b/techpack/audio/include/dsp/msm-cirrus-playback.h @@ -0,0 +1,184 @@ +/* Copyright (c) 2015 Cirrus Logic, Inc. + * + * 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. + */ +#ifndef MSM_CIRRUS_PLAYBACK_H +#define MSM_CIRRUS_PLAYBACK_H +#define DEBUG +#include +#include +#include +#include +#include +#include + + +#define MIN_CHAN_SWAP_SAMPLES 48 +#define MAX_CHAN_SWAP_SAMPLES 9600 +#define VOL_ATTN_MAX 0x7FFFFFFF +#define VOL_ATTN_18DB 257698038 +#define VOL_ATTN_24DB 128849019 + +struct afe_cspl_state { + void **apr; + atomic_t *status; + atomic_t *state; + wait_queue_head_t *wait; + int timeout_ms; +}; + +extern struct afe_cspl_state cspl_afe; + +struct afe_custom_crus_set_config_v2_t { + struct apr_hdr hdr; + struct afe_port_cmd_set_param_v2 param; + struct param_hdr_v2 data; +} __packed; + +struct afe_custom_crus_get_config_v2_t { + struct apr_hdr hdr; + struct afe_port_cmd_get_param_v2 param; + struct param_hdr_v2 data; +} __packed; + +struct afe_custom_crus_set_config_t { + struct apr_hdr hdr; + struct afe_port_cmd_set_param_v3 param; + struct param_hdr_v3 data; +} __packed; + +struct afe_custom_crus_get_config_t { + struct apr_hdr hdr; + struct afe_port_cmd_get_param_v3 param; + struct param_hdr_v3 data; +} __packed; + +/* Payload struct for getting or setting one integer value from/to the DSP module */ +struct crus_single_data_t { + int32_t value; +}; + +/* Payload struct for getting or setting two integer values from/to the DSP module */ +struct crus_dual_data_t { + int32_t data1; + int32_t data2; +}; + +/* Payload struct for getting or setting three integer values from/to the DSP module */ +struct crus_triple_data_t { + int32_t data1; + int32_t data2; + int32_t data3; +}; + +/* Payload struct for setting the RX and TX use cases */ +struct crus_rx_run_case_ctrl_t { + int32_t value; + int32_t status_l; + int32_t checksum_l; + int32_t z_l; + int32_t status_r; + int32_t checksum_r; + int32_t z_r; + int32_t atemp; +}; + +/* Payload struct for getting calibration result from DSP module */ +struct cirrus_cal_result_t { + int32_t status_l; + int32_t checksum_l; + int32_t z_l; + int32_t status_r; + int32_t checksum_r; + int32_t z_r; +}; + +#define APR_CHUNK_SIZE 256 + +/* Payload struct for sending an external configuration string to the DSP + * module + */ +struct crus_external_config_t { + uint32_t total_size; + uint32_t chunk_size; + int32_t done; + int32_t reserved; + int32_t config; + char data[APR_CHUNK_SIZE]; +}; +/* Payload struct for sending an external tuning transition string to the DSP + * module + */ +struct crus_delta_config_t { + uint32_t total_size; + uint32_t chunk_size; + int32_t done; + int32_t index; + int32_t reserved; + int32_t config; + char data[APR_CHUNK_SIZE]; +}; + +struct crus_rx_temperature_t { + uint32_t cal_status_l; + uint32_t temp_r; + uint32_t z_r; + uint32_t temp_l; + uint32_t z_l; + uint32_t cal_status_r; + uint32_t amb_temp_l; + uint32_t excur_model_r; + uint32_t excur_model_l; + uint32_t cksum_r; + uint32_t amb_temp_r; + uint32_t cksum_l; + uint32_t hp_status_l; + uint32_t full_status_l; + uint32_t hp_status_r; + uint32_t full_status_r; +}; + +#define CONFIG_FILE_SIZE 128 +#define PAYLOAD_FOLLOWS_CONFIG 4 +#define MAX_TUNING_CONFIGS 4 +#define MIN_CHAN_SWAP_SAMPLES 48 +#define MAX_CHAN_SWAP_SAMPLES 9600 +#define CRUS_MAX_BUFFER_SIZE 384 + +struct crus_control_t { + struct device *device; + int32_t q6afe_rev; + bool afe_start; + bool enable; + bool prot_en; + int32_t fb_port_index; + int32_t fb_port; + int32_t ff_port; + int ch_sw_duration; + int32_t ch_sw; + int32_t vol_atten; + atomic_t callback_wait; + atomic_t count_wait; + struct mutex param_lock; + struct mutex sp_lock; + int32_t* user_buffer; + int32_t usecase; + int32_t config; + int32_t conf_sel; + int32_t delta_sel; + int32_t usecase_dt_count; +}; + +//extern int afe_apr_send_pkt_crus(void *data, int index, int set); + +int crus_afe_callback(void* payload, int size); +void msm_crus_pb_add_controls(struct snd_soc_platform *platform); +#endif /* _MSM_CIRRUS_PLAYBACK_H */ + diff --git a/techpack/audio/include/dsp/q6afe-v2.h b/techpack/audio/include/dsp/q6afe-v2.h index 942e882698c6..3e1790faea1a 100644 --- a/techpack/audio/include/dsp/q6afe-v2.h +++ b/techpack/audio/include/dsp/q6afe-v2.h @@ -259,12 +259,14 @@ enum { IDX_SECONDARY_SPDIF_RX, IDX_PRIMARY_SPDIF_TX, IDX_SECONDARY_SPDIF_TX, + /* IDX 185 to 186 */ IDX_SLIMBUS_9_RX, IDX_SLIMBUS_9_TX, /* IDX 187 -> 189 */ IDX_AFE_PORT_ID_SENARY_PCM_RX, IDX_AFE_PORT_ID_SENARY_PCM_TX, + IDX_AFE_PORT_ID_PSEUDOPORT_01, AFE_MAX_PORTS }; @@ -456,6 +458,13 @@ int afe_get_sp_rx_tmax_xmax_logging_data( u16 port_id); int afe_cal_init_hwdep(void *card); int afe_send_port_island_mode(u16 port_id); + +#ifdef CONFIG_MSM_CSPL +int afe_apr_send_pkt_crus(void *data, int index, int set); +int crus_afe_port_close(u16 port_id); +int crus_afe_port_start(u16 port_id); +#endif + int afe_send_cmd_wakeup_register(void *handle, bool enable); void afe_register_wakeup_irq_callback( void (*afe_cb_wakeup_irq)(void *handle)); diff --git a/techpack/audio/include/elliptic/elliptic_data_io.h b/techpack/audio/include/elliptic/elliptic_data_io.h new file mode 100755 index 000000000000..43841ed3e044 --- /dev/null +++ b/techpack/audio/include/elliptic/elliptic_data_io.h @@ -0,0 +1,155 @@ +/** +* Copyright Elliptic Labs 2015-2016 +* +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#define ELLIPTIC_DATA_IO_AP_TO_DSP 0 +#define ELLIPTIC_DATA_IO_DSP_TO_AP 1 + +#define ELLIPTIC_DATA_IO_READ_OK 0 +#define ELLIPTIC_DATA_IO_READ_BUSY 1 +#define ELLIPTIC_DATA_IO_READ_CANCEL 2 + +#define ELLIPTIC_MSG_BUF_SIZE 512 + +/* wake source timeout in ms*/ +#define ELLIPTIC_WAKEUP_TIMEOUT 250 + +#define ELLIPTIC_DATA_FIFO_SIZE (PAGE_SIZE) + +#define ULTRASOUND_RX_PORT_ID 0 +#define ULTRASOUND_TX_PORT_ID 1 + +/* Elliptic Labs UltraSound Module */ +#define ELLIPTIC_ULTRASOUND_DISABLE 0 +#define ELLIPTIC_ULTRASOUND_ENABLE 1 +#define ELLIPTIC_ULTRASOUND_SET_PARAMS 2 +#define ELLIPTIC_ULTRASOUND_GET_PARAMS 3 +#define ELLIPTIC_ULTRASOUND_RAMP_DOWN 4 + +/** Param ID definition */ +#define ELLIPTIC_ULTRASOUND_PARAM_ID_ENGINE_DATA 3 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_CALIBRATION_DATA 11 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_ENGINE_VERSION 12 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_BUILD_BRANCH 14 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_CALIBRATION_V2_DATA 15 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_SENSORHUB 16 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_DIAGNOSTICS_DATA 17 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_TAG 18 +#define ELLIPTIC_ULTRASOUND_PARAM_ID_ML_DATA 19 + +#define ELLIPTIC_DATA_READ_BUSY 0 +#define ELLIPTIC_DATA_READ_OK 1 +#define ELLIPTIC_DATA_READ_CANCEL 2 + +#define ELLIPTIC_ALL_DEVICES -1 +#define ELLIPTIC_DEVICE_0 0 +#define ELLIPTIC_DEVICE_1 1 + +enum elliptic_message_id { + ELLIPTIC_MESSAGE_PAYLOAD, /* Input to AP*/ + ELLIPTIC_MESSAGE_RAW, /* Output from AP*/ + ELLIPTIC_MESSAGE_CALIBRATION, + ELLIPTIC_MESSAGE_CALIBRATION_V2, + ELLIPTIC_MESSAGE_DIAGNOSTICS, + ELLIPTIC_MAX_MESSAGE_IDS +}; + +typedef enum { + ELLIPTIC_DATA_PUSH_FROM_KERNEL, + ELLIPTIC_DATA_PUSH_FROM_USERSPACE +} elliptic_data_push_t; + +struct elliptic_data { + /* wake lock timeout */ + unsigned int wakeup_timeout; + + /* members for top half interrupt handling */ + struct kfifo fifo_isr; + spinlock_t fifo_isr_spinlock; + wait_queue_head_t fifo_isr_not_empty; + struct mutex user_buffer_lock; + + /* buffer to swap data from isr fifo to userspace */ + uint8_t isr_swap_buffer[ELLIPTIC_MSG_BUF_SIZE]; + + atomic_t abort_io; + + /* debug counters, reset between open/close */ + uint32_t isr_fifo_discard; + + /* debug counters, persistent */ + uint32_t isr_fifo_discard_total; + uint32_t userspace_read_total; + uint32_t isr_write_total; + +}; + +/* Elliptic IO module API (implemented by IO module)*/ + +int elliptic_data_io_initialize(void); +int elliptic_data_io_cleanup(void); + +int32_t elliptic_data_io_write(uint32_t message_id, const char *data, + size_t data_size); + +int32_t elliptic_data_io_transact(uint32_t message_id, const char *data, + size_t data_size, char *output_data, size_t output_data_size); + + +/* Elliptic driver API (implemented by main driver)*/ +int elliptic_data_initialize(struct elliptic_data *, + size_t max_queue_size, unsigned int wakeup_timeout, int id); + +int elliptic_data_cleanup(struct elliptic_data *); + +void elliptic_data_reset_debug_counters(struct elliptic_data *); +void elliptic_data_update_debug_counters(struct elliptic_data *); +void elliptic_data_print_debug_counters(struct elliptic_data *); + +/* Called from elliptic device read */ +size_t elliptic_data_pop(struct elliptic_data *, + char __user *buffer, size_t buffer_size); + +/* Used for cancelling a blocking read */ +void elliptic_data_cancel(struct elliptic_data *); + +/* Called from IO module*/ +int elliptic_data_push(int deviceid, const char *buffer, size_t buffer_size, elliptic_data_push_t); + +/* Writes to io module and user space control */ +int32_t elliptic_data_write(uint32_t message_id, + const char *data, size_t data_size); + +/* Opens port */ +int elliptic_open_port(int portid); + +/* Closes port */ +int elliptic_close_port(int portid); + +/* Opens port */ +int elliptic_io_open_port(int portid); + +/* Closes port */ +int elliptic_io_close_port(int portid); + +/* Create device node for userspace io driver*/ +int elliptic_userspace_io_driver_init(void); +void elliptic_userspace_io_driver_exit(void); + +/* Create device node for userspace io driver*/ +int elliptic_userspace_ctrl_driver_init(void); +void elliptic_userspace_ctrl_driver_exit(void); +int32_t elliptic_userspace_ctrl_write(uint32_t message_id, + const char *data, size_t data_size); + diff --git a/techpack/audio/include/elliptic/elliptic_device.h b/techpack/audio/include/elliptic/elliptic_device.h new file mode 100755 index 000000000000..78159257cead --- /dev/null +++ b/techpack/audio/include/elliptic/elliptic_device.h @@ -0,0 +1,54 @@ +/** + * Copyright Elliptic Labs + * + */ + +#pragma once + +#include +#include +#include +#include + +#define ELLIPTIC_DEVICENAME "elliptic" +#define ELLIPTIC_NUM_DEVICES 2 + +#define IOCTL_ELLIPTIC_APP 197 +#define MIRROR_TAG 0x3D0A4842 + +#define IOCTL_ELLIPTIC_DATA_IO_CANCEL \ + _IO(IOCTL_ELLIPTIC_APP, 2) + +#define IOCTL_ELLIPTIC_ACTIVATE_ENGINE \ + _IOW(IOCTL_ELLIPTIC_APP, 3, int) + +#define IOCTL_ELLIPTIC_SET_RAMP_DOWN \ + _IO(IOCTL_ELLIPTIC_APP, 4) + +#define IOCTL_ELLIPTIC_SYSTEM_CONFIGURATION \ + _IOW(IOCTL_ELLIPTIC_APP, 5, int) + +#define IOCTL_ELLIPTIC_DATA_IO_MIRROR \ + _IOW(IOCTL_ELLIPTIC_APP, 117, unsigned char *) + +struct elliptic_device { + int opened; + struct cdev cdev; + struct semaphore sem; + struct elliptic_data el_data; +}; + +extern struct class *elliptic_class; + +#define EL_PRINT_E(string, arg...) \ + pr_err("[ELUS] : (%s) : " string "\n", __func__, ##arg) + +#define EL_PRINT_W(string, arg...) \ + pr_warn("[ELUS] : (%s) : " string "\n", __func__, ##arg) + +#define EL_PRINT_I(string, arg...) \ + pr_info("[ELUS] : (%s) : " string "\n", __func__, ##arg) + +#define EL_PRINT_D(string, arg...) \ + pr_debug("[ELUS] : (%s) : " string "\n", __func__, ##arg) + diff --git a/techpack/audio/include/elliptic/elliptic_mixer_controls.h b/techpack/audio/include/elliptic/elliptic_mixer_controls.h new file mode 100755 index 000000000000..190f34703a19 --- /dev/null +++ b/techpack/audio/include/elliptic/elliptic_mixer_controls.h @@ -0,0 +1,188 @@ +#pragma once +#include +#include +#include +#include + + +#define ELLIPTIC_OBJ_ID_CALIBRATION_DATA 1 +#define ELLIPTIC_OBJ_ID_VERSION_INFO 2 +#define ELLIPTIC_OBJ_ID_BRANCH_INFO 3 +#define ELLIPTIC_OBJ_ID_CALIBRATION_V2_DATA 4 +#define ELLIPTIC_OBJ_ID_DIAGNOSTICS_DATA 5 +#define ELLIPTIC_OBJ_ID_TAG_INFO 6 +#define ELLIPTIC_OBJ_ID_ML_DATA 7 + +#define ELLIPTIC_SYSTEM_CONFIGURATION_SIZE 96 +#define ELLIPTIC_CALIBRATION_DATA_SIZE 64 +#define ELLIPTIC_CALIBRATION_V2_DATA_SIZE 448 +#define ELLIPTIC_DIAGNOSTICS_DATA_SIZE 448 +#define ELLIPTIC_DIAGNOSTICS_U32_DATA_VALUES (ELLIPTIC_DIAGNOSTICS_DATA_SIZE>>2) +#define ELLIPTIC_SENSOR_DATA_SIZE 68 +#define ELLIPTIC_SENSOR_U32_DATA_VALUES (ELLIPTIC_SENSOR_DATA_SIZE>>2) +#define ELLIPTIC_VERSION_INFO_SIZE 16 +#define ELLIPTIC_BRANCH_INFO_SIZE 32 +#define ELLIPTIC_BRANCH_INFO_MAX_SIZE 128 +#define ELLIPTIC_TAG_INFO_SIZE 32 +#define ELLIPTIC_ML_DATA_SIZE 432 + +#define ELLIPTIC_ULTRASOUND_DISABLE 0 +#define ELLIPTIC_ULTRASOUND_ENABLE 1 +#define ELLIPTIC_ULTRASOUND_SET_PARAMS 2 +#define ELLIPTIC_ULTRASOUND_GET_PARAMS 3 +#define ELLIPTIC_ULTRASOUND_RAMP_DOWN 4 + +/** register */ +#define ELLIPTIC_CALIBRATION 1 +/** bits */ +#define ELLIPTIC_CALIBRATION_STATE 0 +#define ELLIPTIC_CALIBRATION_PROFILE 1 +#define ELLIPTIC_ULTRASOUND_GAIN 2 + +/** custom settings */ +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_COUNT 16 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_MAX_VALUE 0x7FFFFFFF + + +/** register */ +#define ELLIPTIC_SYSTEM_CONFIGURATION 0 +/** bits */ +#define ELLIPTIC_SYSTEM_CONFIGURATION_LATENCY 0 +#define ELLIPTIC_SYSTEM_CONFIGURATION_SENSITIVITY 1 +#define ELLIPTIC_SYSTEM_CONFIGURATION_SPEAKER_SCALING 2 +#define ELLIPTIC_SYSTEM_CONFIGURATION_MICROPHONE_INDEX 3 +#define ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE 4 +#define ELLIPTIC_SYSTEM_CONFIGURATION_OPERATION_MODE_FLAGS 5 +#define ELLIPTIC_SYSTEM_CONFIGURATION_LOG_LEVEL 6 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_0 7 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_1 8 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_2 9 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_3 10 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_4 11 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_5 12 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_6 13 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_7 14 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_8 15 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_9 16 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_10 17 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_11 18 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_12 19 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_13 20 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_14 21 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_15 22 + +#define ELLIPTIC_SYSTEM_CONFIGURATION_SUSPEND 23 +#define ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_ENABLED 24 +#define ELLIPTIC_SYSTEM_CONFIGURATION_OUTPUT_ENABLED 25 +#define ELLIPTIC_SYSTEM_CONFIGURATION_EXTERNAL_EVENT 26 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CALIBRATION_METHOD 27 +#define ELLIPTIC_SYSTEM_CONFIGURATION_DEBUG_MODE 28 +#define ELLIPTIC_SYSTEM_CONFIGURATION_NUMBER_OF_RUNS 29 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CONTEXT 30 +#define ELLIPTIC_SYSTEM_CONFIGURATION_CAPTURE 31 +#define ELLIPTIC_SYSTEM_CONFIGURATION_INPUT_CHANNELS 32 + +#define ELLIPTIC_SYSTEM_CONFIGURATION_MAX_CONTEXT_VALUE 0x7FFFFFFF + + +struct elliptic_engine_version_info { + uint32_t major; + uint32_t minor; + uint32_t build; + uint32_t revision; +}; + +struct elliptic_shared_data_block { + uint32_t object_id; + size_t size; + void *buffer; +}; + +struct elliptic_shared_data_block *elliptic_get_shared_obj(uint32_t + object_id); + +extern unsigned int elliptic_add_platform_controls(void *platform); + +void elliptic_set_calibration_data(uint8_t *calib_data, size_t size); + +enum elliptic_system_configuration_parameter_type { + + ESCPT_SPEAKER_SCALING = 1, + ESCPT_CHANNEL_SENSITIVITY, + ESCPT_LATENCY, + ESCPT_MICROPHONE_INDEX, + ESCPT_OPERATION_MODE, + ESCPT_OPERATION_MODE_FLAGS, + ESCPT_COMPONENT_GAIN_CHANGE, + ESCPT_CALIBRATION_STATE, + ESCPT_ENGINE_VERSION, + ESCPT_CALIBRATION_PROFILE, + ESCPT_ULTRASOUND_GAIN, + ESCPT_LOG_LEVEL, + ESCPT_BUILD_BRANCH, //13 + + ESCPT_FSELECTION, + ESCPT_ENGINE_DIAGNOSTICS, + ESCPT_ENGINE_CUSTOM_SETTING_0, + ESCPT_ENGINE_CUSTOM_SETTING_1, + ESCPT_ENGINE_CUSTOM_SETTING_2, + ESCPT_ENGINE_CUSTOM_SETTING_3, + ESCPT_ENGINE_CUSTOM_SETTING_4, + ESCPT_ENGINE_CUSTOM_SETTING_5, + ESCPT_ENGINE_CUSTOM_SETTING_6, + ESCPT_ENGINE_CUSTOM_SETTING_7, + ESCPT_ENGINE_CUSTOM_SETTING_8, + ESCPT_ENGINE_CUSTOM_SETTING_9, + ESCPT_ENGINE_CUSTOM_SETTING_10, + ESCPT_ENGINE_CUSTOM_SETTING_11, + ESCPT_ENGINE_CUSTOM_SETTING_12, + ESCPT_ENGINE_CUSTOM_SETTING_13, + ESCPT_ENGINE_CUSTOM_SETTING_14, + ESCPT_ENGINE_CUSTOM_SETTING_15, + ESCPT_SUSPEND, // 32 + ESCPT_INPUT_ENABLED, + ESCPT_OUTPUT_ENABLED, + ESCPT_EXTERNAL_EVENT, + ESCPT_ENGINE_TAG, //36 + ESCPT_CALIBRATION_METHOD, + ESCPT_DEBUG_MODE, + ESCPT_NUMBER_OF_RUNS, + ESCPT_CONTEXT, + ESCPT_CAPTURE, + ESCPT_INPUT_CHANNELS, +}; + +struct elliptic_system_configuration_parameters_cache { + int32_t speaker_scaling[2]; + int32_t sensitivity; + int32_t latency; + int32_t microphone_index; + int32_t operation_mode; + int32_t operation_mode_flags; + int32_t component_gain_change; + int32_t calibration_state; + int32_t engine_version; + int32_t calibration_profile; + int32_t ultrasound_gain; + int32_t log_level; + int32_t custom_settings[ELLIPTIC_SYSTEM_CONFIGURATION_CUSTOM_SETTING_COUNT]; + int32_t engine_suspend; + int32_t input_enabled; + int32_t output_enabled; + int32_t external_event; + int32_t calibration_method; + int32_t debug_mode; + int32_t number_of_runs; + int32_t context; + int32_t capture; + int32_t input_channels; +}; + + +int elliptic_trigger_version_msg(void); + +int elliptic_trigger_branch_msg(void); + +int elliptic_trigger_tag_msg(void); + +int elliptic_trigger_diagnostics_msg(void); diff --git a/techpack/audio/include/elliptic/elliptic_sysfs.h b/techpack/audio/include/elliptic/elliptic_sysfs.h new file mode 100755 index 000000000000..23f9d19d8ebd --- /dev/null +++ b/techpack/audio/include/elliptic/elliptic_sysfs.h @@ -0,0 +1,15 @@ +#pragma once + +#define ELLIPTIC_SYSFS_ENGINE_FOLDER "engine" +#define ELLIPTIC_SYSFS_ROOT_FOLDER "elliptic" +#define ELLIPTIC_SYSFS_CALIBRATION_FILENAME "calibration" +#define ELLIPTIC_SYSFS_VERSION_FILENAME "version" +#define ELLIPTIC_SYSFS_CALIBRATION_V2_FILENAME "calibration_v2" +#define ELLIPTIC_SYSFS_STATE_FILENAME "state" +#define ELLIPTIC_SYSFS_TAG_FILENAME "tag" +#define ELLIPTIC_SYSFS_OPMODE_FILENAME "opmode" +#define ELLIPTIC_SYSFS_OPMODE_FLAGS_FILENAME "opmode_flags" + + +int elliptic_initialize_sysfs(void); +void elliptic_cleanup_sysfs(void); diff --git a/techpack/audio/include/soc/internal.h b/techpack/audio/include/soc/internal.h index ad0a98dfc101..2bc065526db0 120000 --- a/techpack/audio/include/soc/internal.h +++ b/techpack/audio/include/soc/internal.h @@ -1 +1 @@ -../../../../../../kernel/msm-4.14/drivers/base/regmap/internal.h \ No newline at end of file +../../../../drivers/base/regmap/internal.h \ No newline at end of file diff --git a/techpack/audio/include/uapi/Android.mk b/techpack/audio/include/uapi/Android.mk deleted file mode 100644 index b8c209adaa0e..000000000000 --- a/techpack/audio/include/uapi/Android.mk +++ /dev/null @@ -1,29 +0,0 @@ -# Use this by setting -# LOCAL_HEADER_LIBRARIES := audio_kernel_headers - -LOCAL_PATH := $(call my-dir) -MYLOCAL_PATH := $(LOCAL_PATH) - -UAPI_OUT := $(PRODUCT_OUT)/obj/vendor/qcom/opensource/audio-kernel/include - -AUDIO_KERNEL_HEADERS := $(call all-named-files-under,*.h,linux) $(call all-named-files-under,*.h,sound) - -HEADER_INSTALL_DIR := kernel/msm-$(TARGET_KERNEL_VERSION)/scripts - -BUILD_ROOT_RELATIVE := ../../../../../../../ - -include $(CLEAR_VARS) -LOCAL_MODULE := audio_kernel_headers -LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_PREBUILT_INT_KERNEL) - -GEN := $(addprefix $(UAPI_OUT)/,$(AUDIO_KERNEL_HEADERS)) -$(GEN): $(KERNEL_USR) -$(GEN): PRIVATE_PATH := $(MYLOCAL_PATH) -$(GEN): PRIVATE_CUSTOM_TOOL = $(shell cd $(PRODUCT_OUT)/obj/KERNEL_OBJ; $(BUILD_ROOT_RELATIVE)$(HEADER_INSTALL_DIR)/headers_install.sh $(BUILD_ROOT_RELATIVE)$(dir $@) $(BUILD_ROOT_RELATIVE)$(subst $(UAPI_OUT),$(MYLOCAL_PATH),$(dir $@)) $(notdir $@)) -$(GEN): $(addprefix $(MYLOCAL_PATH)/,$(AUDIO_KERNEL_HEADERS)) - $(transform-generated-source) - -LOCAL_GENERATED_SOURCES := $(GEN) -LOCAL_EXPORT_C_INCLUDE_DIRS := $(UAPI_OUT) - -include $(BUILD_HEADER_LIBRARY) diff --git a/techpack/audio/include/uapi/sound/cs35l41.h b/techpack/audio/include/uapi/sound/cs35l41.h new file mode 100644 index 000000000000..a3f7e537f6b8 --- /dev/null +++ b/techpack/audio/include/uapi/sound/cs35l41.h @@ -0,0 +1,83 @@ +/* + * linux/sound/cs35l41.h -- Platform data for CS35L41 + * + * Copyright (c) 2018 Cirrus Logic Inc. + * + * 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. + */ + +#ifndef __CS35L41_H +#define __CS35L41_H + +struct classh_cfg { + bool classh_bst_override; + bool classh_algo_enable; + int classh_bst_max_limit; + int classh_mem_depth; + int classh_release_rate; + int classh_headroom; + int classh_wk_fet_delay; + int classh_wk_fet_thld; +}; + +struct irq_cfg { + bool is_present; + bool irq_pol_inv; + bool irq_out_en; + int irq_src_sel; +}; + +struct cs35l41_platform_data { + bool sclk_frc; + bool lrclk_frc; + bool right_channel; + bool amp_gain_zc; + bool ng_enable; + int bst_ind; + int bst_vctrl; + int bst_ipk; + int bst_cap; + int temp_warn_thld; + int ng_pcm_thld; + int ng_delay; + int dout_hiz; + struct irq_cfg irq_config1; + struct irq_cfg irq_config2; + struct classh_cfg classh_config; + int mnSpkType; + struct device_node *spk_id_gpio_p; +}; + +struct cs35l41_private { + struct wm_adsp dsp; /* needs to be first member */ + struct snd_soc_codec *codec; + struct cs35l41_platform_data pdata; + struct device *dev; + struct regmap *regmap; + struct regulator_bulk_data supplies[2]; + int num_supplies; + int irq; + int clksrc; + int extclk_freq; + int extclk_cfg; + int sclk; + unsigned int cspl_cmd; + bool dspa_mode; + bool i2s_mode; + bool swire_mode; + bool halo_booted; + bool bus_spi; + /* GPIO for /RST */ + //struct gpio_desc *reset_gpio; + int reset_gpio; + struct completion global_pup_done; + struct completion global_pdn_done; + struct completion mbox_cmd; +}; + +int cs35l41_probe(struct cs35l41_private *cs35l41, + struct cs35l41_platform_data *pdata); +int spk_id_get(struct device_node *np); +#endif /* __CS35L41_H */ diff --git a/techpack/audio/include/uapi/sound/msm-cirrus-playback.h b/techpack/audio/include/uapi/sound/msm-cirrus-playback.h new file mode 100644 index 000000000000..aca17609f26f --- /dev/null +++ b/techpack/audio/include/uapi/sound/msm-cirrus-playback.h @@ -0,0 +1,119 @@ +/* Copyright (c) 2016 Cirrus Logic, Inc. + * + * 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. + */ +#ifndef _UAPI_MSM_CIRRUS_SPK_PR_H +#define _UAPI_MSM_CIRRUS_SPK_PR_H + +#include +#include + + +#define CIRRUS_SP 0x10027053 +#define CIRRUS_SP_ENABLE 0x10002001 + +#define CRUS_MODULE_ID_TX 0x00000002 +#define CRUS_MODULE_ID_RX 0x00000001 + +/* + * CRUS_PARAM_RX/TX_SET_USECASE + * 0 = Music Playback in firmware + * 1 = VOICE Playback in firmware + * 2 = Tuning file loaded using external + * config load command + * + * uses crus_rx_run_case_ctrl for RX apr pckt + * uses crus_single_data_ctrl for TX apr pckt + * + */ +#define CRUS_PARAM_RX_SET_USECASE 0x00A1AF02 +#define CRUS_PARAM_TX_SET_USECASE 0x00A1BF0A +/* + * CRUS_PARAM_RX/TX_SET_CALIB + * Non-zero value to run speaker + * calibration sequence + * + * uses crus_single_data_t apr pckt + */ +#define CRUS_PARAM_RX_SET_CALIB 0x00A1AF03 +#define CRUS_PARAM_TX_SET_CALIB 0x00A1BF03 +/* + * CRUS_PARAM_RX/TX_SET_EXT_CONFIG + * config string loaded from libfirmware + * max of 7K paramters + * + * uses crus_external_config_t apr pckt + */ +#define CRUS_PARAM_RX_SET_EXT_CONFIG 0x00A1AF05 +#define CRUS_PARAM_TX_SET_EXT_CONFIG 0x00A1BF08 +/* + * CRUS_PARAM_RX_GET_TEMP + * get current Temp and calibration data + * + * CRUS_PARAM_TX_GET_TEMP_CAL + * get results of calibration sequence + * + * uses cirrus_cal_result_t apr pckt + */ +#define CRUS_PARAM_RX_GET_TEMP 0x00A1AF07 +#define CRUS_PARAM_TX_GET_TEMP_CAL 0x00A1BF06 +/* + * CRUS_PARAM_RX_SET_DELTA_CONFIG + * load seamless transition config string + * + * CRUS_PARAM_RX_RUN_DELTA_CONFIG + * execute the loaded seamless transition + */ +#define CRUS_PARAM_RX_SET_DELTA_CONFIG 0x00A1AF0D +#define CRUS_PARAM_RX_RUN_DELTA_CONFIG 0x00A1AF0E +/* + * CRUS_PARAM_RX_CHANNEL_SWAP + * initiate l/r channel swap transition + */ +#define CRUS_PARAM_RX_CHANNEL_SWAP 0x00A1AF12 +#define CRUS_PARAM_RX_GET_CHANNEL_SWAP 0x00A1AF13 +/* + * CRUS_PARAM_RX_SET_ATTENUATION + * set volume attenuation in volume control blocks 1 & 2 + */ +#define CRUS_PARAM_RX_SET_ATTENUATION 0x00A1AF0A +#define CRUS_AFE_PARAM_ID_ENABLE 0x00010203 + +#define SPK_PROT_IOCTL_MAGIC 'a' + +#define CRUS_SP_IOCTL_GET _IOWR(SPK_PROT_IOCTL_MAGIC, 219, void *) +#define CRUS_SP_IOCTL_SET _IOWR(SPK_PROT_IOCTL_MAGIC, 220, void *) +#define CRUS_SP_IOCTL_GET_CALIB _IOWR(SPK_PROT_IOCTL_MAGIC, 221, void *) +#define CRUS_SP_IOCTL_SET_CALIB _IOWR(SPK_PROT_IOCTL_MAGIC, 222, void *) +#define CRUS_SP_IOCTL_READ_CALIB_FROM_SLOT _IOWR(SPK_PROT_IOCTL_MAGIC, 223, void *) +#define CRUS_SP_IOCTL_WRITE_CALIB_TO_SLOT _IOWR(SPK_PROT_IOCTL_MAGIC, 224, void *) + +#define CRUS_SP_IOCTL_GET32 _IOWR(SPK_PROT_IOCTL_MAGIC, 219, \ + compat_uptr_t) +#define CRUS_SP_IOCTL_SET32 _IOWR(SPK_PROT_IOCTL_MAGIC, 220, \ + compat_uptr_t) +#define CRUS_SP_IOCTL_GET_CALIB32 _IOWR(SPK_PROT_IOCTL_MAGIC, 221, \ + compat_uptr_t) +#define CRUS_SP_IOCTL_SET_CALIB32 _IOWR(SPK_PROT_IOCTL_MAGIC, 222, \ + compat_uptr_t) +#define CRUS_SP_IOCTL_READ_CALIB_FROM_SLOT32 _IOWR(SPK_PROT_IOCTL_MAGIC, 223, \ + compat_uptr_t) +#define CRUS_SP_IOCTL_WRITE_CALIB_TO_SLOT32 _IOWR(SPK_PROT_IOCTL_MAGIC, 224, \ + compat_uptr_t) + +struct crus_sp_ioctl_header { + uint32_t size; + uint32_t module_id; + uint32_t param_id; + uint32_t data_length; + void *data; +}; + +#endif /* _UAPI_MSM_CIRRUS_SPK_PR_H */ diff --git a/techpack/audio/ipc/Android.mk b/techpack/audio/ipc/Android.mk deleted file mode 100644 index 10d169ea99cf..000000000000 --- a/techpack/audio/ipc/Android.mk +++ /dev/null @@ -1,69 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,sdm845),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m -endif - -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) atoll $(TRINKET)),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile $(MSMSTEPPE) atoll $(TRINKET)),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=apr_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_apr.ko -LOCAL_MODULE_KBUILD_NAME := apr_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_wglink.ko -LOCAL_MODULE_KBUILD_NAME := wglink_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/ipc/Kbuild b/techpack/audio/ipc/Kbuild index 11faab5e1405..a0431e110222 100644 --- a/techpack/audio/ipc/Kbuild +++ b/techpack/audio/ipc/Kbuild @@ -157,6 +157,3 @@ apr_dlkm-y := $(APRV_GLINK) obj-$(CONFIG_WCD_DSP_GLINK) += wglink_dlkm.o wglink_dlkm-y := $(WDSP_GLINK) - -# inject some build related information -CDEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/soc/Android.mk b/techpack/audio/soc/Android.mk deleted file mode 100644 index 8a87a8aa9e09..000000000000 --- a/techpack/audio/soc/Android.mk +++ /dev/null @@ -1,97 +0,0 @@ -# Android makefile for audio kernel modules - -# Assume no targets will be supported - -# Check if this driver needs be built for current target -ifeq ($(call is-board-platform,sdm845),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM845=m -endif - -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605),true) -AUDIO_SELECT := CONFIG_SND_SOC_SDM670=m -endif - -ifeq ($(call is-board-platform,msmnile),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM8150=m -endif - -ifeq ($(call is-board-platform-in-list,$(MSMSTEPPE) $(TRINKET) atoll),true) -AUDIO_SELECT := CONFIG_SND_SOC_SM6150=m -endif - -AUDIO_CHIPSET := audio -# Build/Package only in case of supported target -ifeq ($(call is-board-platform-in-list,msm8953 sdm845 sdm670 qcs605 msmnile $(MSMSTEPPE) $(TRINKET) atoll),true) - -LOCAL_PATH := $(call my-dir) - -# This makefile is only for DLKM -ifneq ($(findstring vendor,$(LOCAL_PATH)),) - -ifneq ($(findstring opensource,$(LOCAL_PATH)),) - AUDIO_BLD_DIR := $(shell pwd)/vendor/qcom/opensource/audio-kernel -endif # opensource - -DLKM_DIR := $(TOP)/device/qcom/common/dlkm - -# Build audio.ko as $(AUDIO_CHIPSET)_audio.ko -########################################################### -# This is set once per LOCAL_PATH, not per (kernel) module -KBUILD_OPTIONS := AUDIO_ROOT=$(AUDIO_BLD_DIR) - -# We are actually building audio.ko here, as per the -# requirement we are specifying _audio.ko as LOCAL_MODULE. -# This means we need to rename the module to _audio.ko -# after audio.ko is built. -KBUILD_OPTIONS += MODNAME=soc_dlkm -KBUILD_OPTIONS += BOARD_PLATFORM=$(TARGET_BOARD_PLATFORM) -KBUILD_OPTIONS += $(AUDIO_SELECT) - -########################################################### -ifeq ($(call is-board-platform-in-list,msm8953 sdm670 qcs605 $(MSMSTEPPE) atoll),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_pinctrl_lpi.ko -LOCAL_MODULE_KBUILD_NAME := pinctrl_lpi_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_pinctrl_wcd.ko -LOCAL_MODULE_KBUILD_NAME := pinctrl_wcd_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_swr.ko -LOCAL_MODULE_KBUILD_NAME := swr_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_swr_ctrl.ko -LOCAL_MODULE_KBUILD_NAME := swr_ctrl_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -########################################################### -ifeq ($(call is-board-platform-in-list, $(MSMSTEPPE) atoll $(TRINKET)),true) -include $(CLEAR_VARS) -LOCAL_MODULE := $(AUDIO_CHIPSET)_snd_event.ko -LOCAL_MODULE_KBUILD_NAME := snd_event_dlkm.ko -LOCAL_MODULE_TAGS := optional -LOCAL_MODULE_DEBUG_ENABLE := true -LOCAL_MODULE_PATH := $(KERNEL_MODULES_OUT) -include $(DLKM_DIR)/AndroidKernelModule.mk -endif -########################################################### - -endif # DLKM check -endif # supported target check diff --git a/techpack/audio/soc/Kbuild b/techpack/audio/soc/Kbuild index 1b37c4f97c24..fc2ce2afc51a 100644 --- a/techpack/audio/soc/Kbuild +++ b/techpack/audio/soc/Kbuild @@ -168,6 +168,3 @@ snd_event_dlkm-y := $(SND_EVENT_OBJS) obj-$(CONFIG_SOUNDWIRE_WCD_CTRL) += swr_ctrl_dlkm.o obj-$(CONFIG_SOUNDWIRE_MSTR_CTRL) += swr_ctrl_dlkm.o swr_ctrl_dlkm-y := $(SWR_CTRL_OBJS) - -# inject some build related information -DEFINES += -DBUILD_TIMESTAMP=\"$(shell date -u +'%Y-%m-%dT%H:%M:%SZ')\" diff --git a/techpack/audio/soc/core.h b/techpack/audio/soc/core.h index b9f94ca74f63..8a2fa90df8cb 120000 --- a/techpack/audio/soc/core.h +++ b/techpack/audio/soc/core.h @@ -1 +1 @@ -../../../../../kernel/msm-4.14/drivers/pinctrl/core.h \ No newline at end of file +../../../drivers/pinctrl/core.h \ No newline at end of file diff --git a/techpack/audio/soc/pinctrl-utils.h b/techpack/audio/soc/pinctrl-utils.h index 0f74549b32c1..9aab5f24bd14 120000 --- a/techpack/audio/soc/pinctrl-utils.h +++ b/techpack/audio/soc/pinctrl-utils.h @@ -1 +1 @@ -../../../../../kernel/msm-4.14/drivers/pinctrl/pinctrl-utils.h \ No newline at end of file +../../../drivers/pinctrl/pinctrl-utils.h \ No newline at end of file